diff --git a/docs/conf.py b/docs/conf.py index 44ca0a0..cafbe7a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,12 +20,12 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) -# -- General configuration ------------------------------------------------ +# -- General Configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' -# Add any Sphinx extension module names here, as strings. They can be +# Add any Sphinx extension module names here as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ @@ -45,7 +45,7 @@ # The encoding of source files. #source_encoding = 'utf-8-sig' -# The master toctree document. +# The master doctree document. master_doc = 'index' # General information about the project. @@ -75,7 +75,7 @@ # directories to ignore when looking for source files. exclude_patterns = ['_build'] -# The reST default role (used for this markup: `text`) to use for all +# The RST default role (used for this markup: `text`) to use for all # documents. #default_role = None @@ -106,8 +106,8 @@ # a list of builtin themes. html_theme = 'default' -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the +# Theme options are theme-specific and customize the look and feel of a theme. +# For a list of options available for each theme, see the # documentation. #html_theme_options = {} @@ -127,7 +127,7 @@ html_logo = 'images/Horizen_UBD_white.svg' # The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = 'images/Horizen_favicon_32x32.png' @@ -197,7 +197,7 @@ htmlhelp_basename = 'Horizen Sidechains SDK' -# -- Options for LaTeX output --------------------------------------------- +# -- Options for LaTeX Output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). @@ -239,7 +239,7 @@ #latex_domain_indices = True -# -- Options for manual page output --------------------------------------- +# -- Options for Manual Page Output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). @@ -252,7 +252,7 @@ #man_show_urls = False -# -- Options for Texinfo output ------------------------------------------- +# -- Options for Texinfo Output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, diff --git a/docs/index.rst b/docs/index.rst index e4eed58..5cbe6f9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,8 +6,8 @@ Horizen Sidechains SDK Documentation Overview ******** -Horizen Sidechain SDK allows developers developers to quickly spin-up their own blockchain, customize business -logic depending on use case, maintain interoperability with the Mainchain native token (which acts as the medium of +Horizen Sidechain SDK allows developers to quickly spin-up their own blockchain, customize business +logic depending on use case, maintain interoperability with the mainchain native token (which acts as the medium of exchange between the whole ecosystem). Sidechain SDK offers out-of-the-box support for the common features you'd expect diff --git a/docs/introduction/01-install.rst b/docs/introduction/01-install.rst index 29b5af4..4003813 100644 --- a/docs/introduction/01-install.rst +++ b/docs/introduction/01-install.rst @@ -1,13 +1,13 @@ .. _install-sidechain-sdk-tutorial: ######################## -Installing Sidechain SDK +Installing the Sidechain SDK ######################## We'll get started by setting up our environment. ******************* -Supported platforms +Supported Platforms ******************* Sidechains-SDK is available and tested on Linux and Windows (64bit). @@ -24,14 +24,14 @@ Horizen Sidechain SDK requires Java 8 or newer (Java 11 recommended), Scala 2.1 Installing on Windows OS: ************************* - 1. Install Java JDK version 11 (link) - 2. Install Scala 2.12.10+ (link) - 3. Install Git (link) + 1. Install Java JDK version 11 (`link `_) + 2. Install Scala 2.12.10+ (`link `_) + 3. Install Git (`link `_) 4. Clone the Sidechains-SDK git repository .. code:: Bash - git clone git@github.com:ZencashOfficial/Sidechains-SDK.git + git clone git@github.com:HorizenOfficial/Sidechains-SDK.git 5. As IDE, please install and use IntelliJ IDEA Community Edition (link) In the IDE, please also install the Intellij Scala plugin: in the Settings->Plugins tab, select it from the marketplace: @@ -46,9 +46,9 @@ Installing on Windows OS: Installing on Linux OS: *********************** - 1. Install Java JDK version 11 (link) - 2. Install Scala 2.12.10+ (link) - 3. Install Git (link) + 1. Install Java JDK version 11 (`link `_) + 2. Install Scala 2.12.10+ (`link `_) + 3. Install Git (`link `_) 4. Clone the Sidechains-SDK git repository .. code:: Bash @@ -60,9 +60,9 @@ Installing on Linux OS: .. image:: /images/intellij.png :alt: IntelliJ - 6. In the IDE, you can now go to File and Open the root directory of the project repository, “\Sidechains-SDK”. The pom.xml file, the Maven’s Project Object Model XML file that contains all the project configuration details should be automatically imported by the IDE. Otherwise, you can just open it. - 7. Keep reading this tutorial, and start playing with the code. You will find some sidechain examples in the “examples/simpleapp” directory, that you can customize, start from there! When you are ready to run your standalone sidechain, you can install Maven (link). - 8. To produce your specific sidechain jar files, you can change directory to the repository root and run the “mvn package” command. + 6. In the IDE, you can now go to File and Open the root directory of the project repository, “\Sidechains-SDK”. The pom.xml file - the Maven Project Object Model XML file that contains all the project configuration details - should be automatically imported by the IDE. Otherwise, you can just open it. + 7. Keep reading this tutorial, and start playing with the code. You will find some sidechain examples in the “examples/simpleapp” directory that you can customize. Start from there! When you are ready to run your own sidechain, you can install Maven (link). + 8. To produce your specific sidechain jar files, you can change the directory to the repository root and run the “mvn package” command. ************************* @@ -71,14 +71,14 @@ Sidechain SDK Components: As a result of step 8, three jar files will be generated: - * **sdk/target/Sidechains-SDK-0.2.0.jar** - the main SDK jar file, that contains all the necessary classes and components; - * **tools/sctool/target/Sidechains-SDK-ScBootstrappingTools-0.2.0.jar** - executable bootstrap tool. It is used to create the configuration of the new Sidechain. You can find all available commands and examples of usage here + * **sdk/target/Sidechains-SDK-0.2.0.jar** - The main SDK jar file that contains all the necessary classes and components + * **tools/sctool/target/Sidechains-SDK-ScBootstrappingTools-0.2.0.jar** - An executable bootstrap tool. It is used to create the configuration of the new Sidechain. You can find all available commands and examples of usage here .. code:: Bash - examples/simpleapp/mc_sc_workflow_example.md file; + examples/simpleapp/mc_sc_workflow_example.md; - * **examples/simpleapp/target/Sidechains-SDK-simpleapp-0.2.0.jar** - in contains a Sidechain application example. You can find more details in the examples/simpleapp/readme.md file. + * **examples/simpleapp/target/Sidechains-SDK-simpleapp-0.2.0.jar** - in contains a sidechain application example. You can find more details in the examples/simpleapp/readme.md file. diff --git a/docs/introduction/02-blockchain-representation.rst b/docs/introduction/02-blockchain-representation.rst index 365285d..8dbfd21 100644 --- a/docs/introduction/02-blockchain-representation.rst +++ b/docs/introduction/02-blockchain-representation.rst @@ -11,7 +11,7 @@ Concept of a BOX **************** A box generalizes the concept of Bitcoin’s UTXOs. -A box is a cryptographic object that can be was created with some secret keys. This box can be opened(spent) by the owner of those secret keys. Once opened by the owner of the secret keys the box may not be opened again. +A box is a cryptographic object that can be created with some secret keys. This box can be open \ (spent) by the owner of those secret keys. Once opened by the owner of the secret keys the box may not be opened again. Node Main elements & intro to a "NodeView" ****************************************** @@ -25,8 +25,7 @@ Node Main elements & intro to a "NodeView" * **Wallet** * The “Wallet” has two main functionalities: 1. It holds the Secret keys that belong to that specific Node. - 2. It keeps track of objects that are of interest to this specific node, e.g. received coins (output boxes whose secret keys are known by the node) and views of them (e.g. balances). - + 2. It keeps track of objects that are of interest to this specific node, e.g. received coins (output boxes whose secret keys are known by the node) and views of them (e.g. balances). * **Memory Pool** * The “Memory pool” is a list of transactions that are known to the node but have not made it to a Sidechain block yet. diff --git a/docs/introduction/03-Cross-chain-transfer-protocol.rst b/docs/introduction/03-Cross-chain-transfer-protocol.rst index 6e4a890..75496ea 100644 --- a/docs/introduction/03-Cross-chain-transfer-protocol.rst +++ b/docs/introduction/03-Cross-chain-transfer-protocol.rst @@ -9,6 +9,7 @@ At a high level, it defines two basic operations: * **forward transfer** * **backward transfer** + While all sidechains know and follow the mainchain, which is an established and stable reality, the mainchain needs to be made aware of the existence of every sidechain. So, sidechains must be declared in mainchain first. We can declare a new sidechain by using the following RPC command: @@ -32,16 +33,20 @@ As a consequence of the sidechain declaration command, a unique sidechain id wil Forward Transfer ================ + A forward transfer sends coins from the mainchain to a sidechain. The Horizen mainchain supports a forward transfer transaction type, that specifies the sidechain destination (sidechain id and receiver address) and the amounts of ZEN to be sent. From a mainchain perspective, the transferred coins are destroyed, they are only represented in the total balance of that particular sidechain. On the sidechain side, the SDK provides all the functionalities that support forward transfers, so that a transferred amount is “converted” into a new sidechain box. + Backward Transfer ================= A backward transfer moves coins back from a sidechain to a mainchain destination. + A backward transfer is initiated by a **withdrawal request** which is a sidechain transaction issued by the coin owner. The request specifies the mainchain destination, and the amount. More precisely, the withdrawal request owner will create a WithdrawalRequestBox that destroys the specified amount of coins in a sidechain. This is not enough to move those coins back to the mainchain though. We need to wait the end of the withdrawal epoch, when all the coins specified in that epoch’s withdrawal requests are listed in a single certificate, that is the propagated to the mainchain. The certificate includes a succinct cryptographic proof that the rules associated with the declared verifying key have been respected. Certificates are processed by mainchain consensus, which recreates the coins specified by the certificate, only checking that the proof verifies and that the coins received by a sidechain are not more than the amount sent to it. + Summary ======= diff --git a/docs/introduction/04-Latus-Consensus.rst b/docs/introduction/04-Latus-Consensus.rst index 1788dcb..77a3e8a 100644 --- a/docs/introduction/04-Latus-Consensus.rst +++ b/docs/introduction/04-Latus-Consensus.rst @@ -15,9 +15,9 @@ A slot leader eligible for a certain slot, that decides to create and propagate Forgers are also entitled and incentivized to include sidechain transactions and mainchain synchronization data into Sidechain Blocks. A limited amount of mainchain block data is added to sidechain blocks, in such a way that all the mainchain transactions that refer to a particular sidechain are included in that sidechain, that a reference to each mainchain block is present in all sidechains, and that enough information is published in a sidechain such that any sidechain node is able to validate the mainchain block references without the need for a direct connection to the mainchain itself. Please note, the forger will need its own direct connection to mainchain nodes, to have a source of mainchain blocks data. -The connection between Mainchain and Sidechain nodes is established via a websocket interface provided by the mainchain node. +The connection between the mainchain and sidechain nodes is established via a websocket interface provided by the mainchain node. -The Latus consensus, including MainchainBlock synchronization and all forging logic and functionality, is implemented out-of-the-box by the SDK Core, and developers do not need to make any change to this. The forging process can be fully managed through the API interface provided by the SDK (see the next topic). +The Latus consensus, including mainchain block synchronization, forging logic and functionality, is implemented out-of-the-box by the core SDK, and developers do not need to make any changes to this. The forging process can be fully managed through the API interface provided by the SDK (see the next topic). Default Latus consensus parameters ================================== diff --git a/docs/introduction/05-Node-communication.rst b/docs/introduction/05-Node-communication.rst index a51a0aa..f10c2cc 100644 --- a/docs/introduction/05-Node-communication.rst +++ b/docs/introduction/05-Node-communication.rst @@ -6,7 +6,7 @@ Communication between a user and a sidechain node is supported out of the box v The API configuration can be found in the sidechain configuration file. -For example see the restApi section of the following file for the SimpleApp. +For example see the restApi section of the following file for the SimpleApp: .. code:: bash @@ -15,7 +15,7 @@ For example see the restApi section of the following file for the SimpleApp. The available options are: -bindAddress -- “IP:port” address for sending HTTP request,e.g. "127.0.0.1:9085" +bindAddress -- “IP:port” address for sending HTTP request, e.g. "127.0.0.1:9085" api-key-hash -- Authentication header must be a string that hashes to the field "api-key-hash" specified in each SC node conf file. Auth header could be empty If no api-key-hash is specified diff --git a/docs/introduction/06-Base-App.rst b/docs/introduction/06-Base-App.rst index 9460af3..6025664 100644 --- a/docs/introduction/06-Base-App.rst +++ b/docs/introduction/06-Base-App.rst @@ -2,26 +2,29 @@ Base App ======== -SidechainsSDK provides to the developers an out of the box implementation of the Latus Consensus Protocol and the Crosschain Transfer Protocol. +Sidechain SDK provides to the developers an out of the box implementation of the Latus Consensus Protocol and the Crosschain Transfer Protocol. Additionally to this, the SDK provides basic transactions, network layer, data storage and node configuration, as well as entry points for any custom extension. Secret / Proof / Proposition **************************** -* **Secret / Proof / Proposition** - SDK uses its own terms for secret key / public key / signed message and provides various types of them. +* **Sidechain SDK** uses its own terms for secret key / public key / signed message and provides various types of them. * **Secret** - Private key * **Proof** - Signed message -* SDK provides implementations for Secret / Proof / Proposition + +* SDK provides the following implementations for Secret / Proof / Proposition * Curve 25519 - PrivateKey25519 - PublicKey25519Proposition - Signature25519 + * VRF based on ginger-lib - VrfSecretKey - VrfPublicKey - VrfProof + * Schnorr based on ginger-lib - SchnorrSecret - SchnorrPropostion @@ -38,7 +41,7 @@ that represents some coins, i.e. that holds an intrinsic defined value. As an ex some kind of smart contract. In particular, any box could be logically split in two parts: Box and BoxData (box data is included in the box). The Box itself represents the entity in the blockchain, i.e. all operations like create/open etc. are performed on boxes. Box data contains information about the entity like value, proposition address and any custom data. -Every box has its own unique boxId (do not be confused with box type id which is used for serialization). That box id is calculated for each box by next function: +Every box has its own unique boxId (not be confused with box type id which is used for serialization). That box id is calculated for each box by next function: :: @@ -60,8 +63,9 @@ Every box has its own unique boxId (do not be confused with box type id which is The following Coin-Box types are provided by SDK: * **RegularBox** -- contains ZEN coins * **ForgerBox** -- contains ZEN coins are used for forging - * **WithdrawalRequestBox** -- contain ZEN coins are used to backward transfer, i.e. move coins back to the mainchain -An SDK developer can declare his own Boxes, please refer to SDK extension section. + * **WithdrawalRequestBox** -- contain ZEN coins are used to backward transfer, i.e. move coins back to the mainchain. + +An SDK developer can declare custom Boxes, please refer to SDK extension section. Transactions ************ @@ -69,7 +73,7 @@ Transactions There are two basic transactions: `MC2SCAggregatedTransaction `_ and `SidechainCoreTransaction `_. -An MC2SCAggregatedTransaction is the implementation of Forward Transfer and can be only added as a part of the MainchainBlock reference data during synchronization with Mainchain. +An MC2SCAggregatedTransaction is the implementation of Forward Transfer and can be only added as a part of the mainchain block reference data during synchronization with mainchain. When a Forger is going to produce a sidechain block and a new mainchain block appears, the forger will recreate that mainchain block as a reference that will contain sidechain related data. So, if some Forward Transfer exists in the mainchain block, it will be included into the MC2SCAggregatedTransaction and added as a part of the reference. The SidechainCoreTransaction is the transaction, which can be created by anyone to send coins inside a sidechain, create forging stakes or perform withdrawal requests diff --git a/docs/introduction/07-Sidechain-SDK-extension.rst b/docs/introduction/07-Sidechain-SDK-extension.rst index 02c771c..f95bc0f 100644 --- a/docs/introduction/07-Sidechain-SDK-extension.rst +++ b/docs/introduction/07-Sidechain-SDK-extension.rst @@ -1,6 +1,6 @@ -======================= -Sidechain SDK extension -======================= +======================== +Sidechains SDK extension +======================== Data serialization @@ -14,6 +14,7 @@ CustomData are the following: For CustomData :: Implement BytesSerializable interface + i.e. :: functions byte[] bytes() @@ -172,21 +173,39 @@ That base class provide next data by default: If the box type is a Coin-Box then this value is required and will contain data such as coin value. In the case of a Non-Coin box this value would only be used in custom logic and cannot be null. Typically we would set this value to 1. So the creation of new Custom Box Data will be created in following way: -``public class CustomBoxData extends AbstractNoncedBoxData`` +:: + public class CustomBoxData extends AbstractNoncedBoxData The new custom box data class requires the following: 1. Custom data definition * Custom data itself - * Hash of all added custom data shall be returned in ``public byte[] customFieldsHash()`` method, otherwise custom data will not be “protected”, i.e. some malicious actor could change custom data during transaction creation. + * Hash of all added custom data shall be returned in + :: + public byte[] customFieldsHash() + + method, otherwise custom data will not be “protected”, i.e. some malicious actor could change custom data during transaction creation. 2. Serialization definition - * Serialization to bytes shall be provided by Custom Box Data by overriding and implementing the method ```public byte[] bytes()```. That method will serialize the proposition, value and any added custom data. - * Additionally definition of Custom Box Data id for serialization by overriding ```public byte boxDataTypeId()``` method, please check the serialization chapter for more information about using ids. - * Override ```public NoncedBoxDataSerializer serializer()``` method with proper **Custom Box Data serializer**. Parsing Custom Box Data from bytes could be defined in that class as well, please refer to the serialization section for more information about it + * Serialization to bytes shall be provided by Custom Box Data by overriding and implementing the method + :: + public byte[] bytes() + + That method will serialize the proposition, value and any added custom data. + * Additionally definition of Custom Box Data id for serialization by overriding + :: + public byte boxDataTypeId() + + method, please check the serialization chapter for more information about using ids. + * Override + :: + public NoncedBoxDataSerializer serializer() + method with proper **Custom Box Data serializer**. Parsing Custom Box Data from bytes could be defined in that class as well, please refer to the serialization section for more information about it 3. Custom Box creation - * Any Box Data class shall provide the way how to create a new Box for a given nonce. For that purpose override the method ```public CustomBox getBox(long nonce)```. + * Any Box Data class shall provide the way how to create a new Box for a given nonce. For that purpose override the method + :: + public CustomBox getBox(long nonce) Custom Box Data Serializer class creation @@ -195,64 +214,94 @@ Custom Box Data Serializer class creation The SDK provides a base class for Custom Box Data Serializer NoncedBoxDataSerializer where D is type of serialized Custom Box Data So creation of a Custom Box Data Serializer can be done in following way: - :: - public class CustomBoxDataSerializer implements NoncedBoxDataSerializer + public class CustomBoxDataSerializer implements NoncedBoxDataSerializer That new Custom Box Data Serializer require's the following: - 1. Definition of function for writing Custom Box Data into the Scorex Writer by implementation of ``public void serialize(CustomBoxData boxData, Writer writer)`` method. + 1. Definition of function for writing Custom Box Data into the Scorex Writer by implementation of the following method. + :: + public void serialize(CustomBoxData boxData, Writer writer) - 2. Definition of function for reading Custom Box Data from Scorex Reader -by implementation of function public CustomBoxData parse(Reader reader) + 2. Definition of function for reading Custom Box Data from Scorex Reader by implementation of the function + :: + public CustomBoxData parse(Reader reader) 3. Class shall be converted to singleton, for example it can be done in following way: -:: - - private static final CustomBoxDataSerializer serializer = new CustomBoxDataSerializer(); + :: + + private static final CustomBoxDataSerializer serializer = new CustomBoxDataSerializer(); - private CustomBoxDataSerializer() { - super(); - } + private CustomBoxDataSerializer() { + super(); + } - public static CustomBoxDataSerializer getSerializer() { - return serializer; - } + public static CustomBoxDataSerializer getSerializer() { + return serializer; + } Custom Box class creation ######################### -The SDK provides base class for creation of a Custom Box: +The SDK provides a base class for creation of a Custom Box: +:: + public class CustomBox extends AbstractNoncedBox + +As parameters for **AbstractNoncedBox** three template parameters shall be provided: +- Proposition type for the box, for common purposes. PublicKey25519Proposition could be used as it used in regular boxes + :: + P extends Proposition -:code:`public class CustomBox extends AbstractNoncedBox` +- Definition of type for Box Data which contains all custom data for a new custom box + :: + BD extends AbstractNoncedBoxData -As a parameters for **AbstractNoncedBox** three template parameters shall be provided: -``P extends Proposition``- Proposition type for the box, for common purposes -PublicKey25519Proposition could be used as it used in regular boxes -``BD extends AbstractNoncedBoxData`` -- Definition of type for Box Data which contains all custom data for new custom box -``B extends AbstractNoncedBox`` -- Definition of type for Box itself, required for description inside of new Custom Box data. +- Definition of type for Box itself, required for description inside of new Custom Box data. + :: + B extends AbstractNoncedBox -The Custom Box itself require's implementation of following functionality: +The Custom Box itself requires implementation of following functionality: 1. Serialization definition - * Box itself shall provide the way to be serialized into bytes, thus method ``public byte[] bytes()`` shall be implemented - * Method ``public static CarBox parseBytes(byte[] bytes)`` for creation of a new Car Box object from bytes, - * Providing box type id by implementation of method ``public byte boxTypeId()`` which return custom box type id. And, finally, proper serializer for the Custom Box shall be returned by implementation of method ``public BoxSerializer serializer()`` + * The box itself provides the way to be serialized into bytes, thus method + :: + public byte[] bytes()`` shall be implemented + * Method for creation of a new Car Box object from bytes + :: + public static CarBox parseBytes(byte[] bytes) + + * Providing box type id by implementation of the following method which return's a custom box type id + :: + public byte boxTypeId() + + And, finally, a serializer for the Custom Box shall be returned by implementation of the following method + :: + public BoxSerializer serializer() Custom Box Serializer Class ########################### -The SDK provides base class for ``Custom Box Serializer -BoxSerializer`` where B is type of serialized Custom Box -So creation of **Custom Box Serializer** can be done in next way: - ``public class CustomBoxSerializer implements NoncedBoxSerializer`` +The SDK provides base class for a custom box serializer below, where B is type of serialized Custom Box +:: + Custom Box Serializer BoxSerializer + +So creation of **Custom Box Serializer** can be done in the following way: +:: + public class CustomBoxSerializer implements NoncedBoxSerializer + The new Custom Box Serializer requires the following: - 1. Definition of method for writing *Custom Box* into the Scorex Writer by implementation of ```public void serialize(CustomBox box, Writer writer)``` method. + 1. Definition of method for writing *Custom Box* into the Scorex Writer by implementation of the following. + :: + public void serialize(CustomBox box, Writer writer) + 2. Definition of method for reading *Custom Box* from Scorex Reader -by implementation of method ```public CustomBox parse(Reader reader) ``` + by implementation of the following + :: + public CustomBox parse(Reader reader) + 3. Class shall be converted to singleton, for example it could be done in following way: :: @@ -276,24 +325,29 @@ A Coin box is created and extended as a usual non-coin box, only one additional Transaction extension ##################### -Transaction in the SDK is represented by ```public abstract class BoxTransaction

> extends Transaction``` class. That class provides access to data like which boxes will be created, unlockers for input boxes, fee, etc. SDK developer could add custom transaction check by implementing *custom ApplicationState* +A transaction in the SDK is represented by the following class. +:: + public abstract class BoxTransaction

> + +This class provides access to data such as which boxes will be created, unlockers for input boxes, fee, etc. +SDK developer could add custom transaction check by implementing *custom ApplicationState* ApplicationState and Wallet ########################### - ApplicationState: +ApplicationState: - :: - - interface ApplicationState { - boolean validate(SidechainStateReader stateReader, SidechainBlock block); +:: - boolean validate(SidechainStateReader stateReader, BoxTransaction> transaction); + interface ApplicationState { + boolean validate(SidechainStateReader stateReader, SidechainBlock block); - Try onApplyChanges(SidechainStateReader stateReader, byte[] version, List> newBoxes, List boxIdsToRemove); + boolean validate(SidechainStateReader stateReader, BoxTransaction> transaction); - Try onRollback(byte[] version); - } + Try onApplyChanges(SidechainStateReader stateReader, byte[] version, List> newBoxes, List boxIdsToRemove); + + Try onRollback(byte[] version); + } For example, the custom application may have the possibility to tokenize cars by creation of Box entries - let’s call them CarBox. Each CarBox token should represent a unique car by having a unique *VIN* (Vehicle Identification Number). To do this Sidechain developer may define ApplicationState to store the list of actual VINs and reject transactions with CarBox tokens with VIN already existing in the system. diff --git a/docs/introduction/08-Car-registry-tutorial.rst b/docs/introduction/08-Car-registry-tutorial.rst index 8578056..25e5b47 100644 --- a/docs/introduction/08-Car-registry-tutorial.rst +++ b/docs/introduction/08-Car-registry-tutorial.rst @@ -3,109 +3,174 @@ Car Registry Tutorial ==================================== Car Registry App high level overview -************************************ +#################################### The Car Registry app is an example of a sidechain that implements specific custom data and logic. The purpose of the application is to manage a simplified service that keeps records of existing cars and their owners. It’s simplified as sidechain users will be able to register cars by simply paying a transaction fee, while in a real world scenario, the ability to create a car will be bound by the presentation of a certificate signed by the Department of Motor Vehicles or analogous authority, or some other consensus -mechanism that guarantees that the car really exists in the real world and it’s owned by a user with a given public key. +mechanism that guarantees that the car exists in the real world and it’s owned by a user with a given public key. Accepting that in our example cars will just show up in sidechain, we want to build an application that can store information that identifies a specific car, such as vehicle identification number, model, production year, color (etc)... A car owner should be able to prove their ownership of the cars without disclosing information about their identity. We also want users to sell and buy cars, with ZEN coins. -So, the starting point of the development process is the data representation. A car is an example of a non-coin box because it represents an entity, but not money. -Another example of a non-coin box is a car which is being sold. We need another box for a selling a car because a common car box doesn't have additional data like sale price, -seller proposition address etc. For the money representation a standard Regular Box is used (Regular box is coin box), that box is provided by SDK. Besides new entities CarBox -and CarSellOrder we also need to define a way for creating/destroying those new entities. For that purpose new transactions can be defined: transaction for creating new car, -transaction which move CarBox to CarSellOrder, transaction which declares a car sale, i.e. moving CarSellOrder to the new CarBox. All created transactions are not put into the -memory pool automatically, so a raw transaction in hex representation by added by creating a /transaction/sendTransaction API request. In summary we will add next car boxes and -transactions: - -Entities: - -+------------------+-----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------+ -| Entity name | Entity description | Entity fields | -+==================+=========================================================================================+=============================================================================================+ -| CarBox | Box which contains car box data, which could be stored and operated in Sidechain | boxData -- contains car box data | -+------------------+-----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------+ -| CarBoxData | Description of the car by using defined properties | vin -- vehicle identification number which contains unique identification number of the car | -| | | year -- vehicle year production | -| | | model -- car model | -| | | color -- car color | -| | | description -- car description | -+------------------+-----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------+ -| CarSellOrder | Box which contains car sell order data, which could be stored and operated in Sidechain | boxData -- contains car sell order data | -+------------------+-----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------+ -| CarSellOrderData | Description of the car which are in sell status | sellerProposition -- seller proposition, i.e. receiver of money for sold car. | -| | | vin -- selling car vin | -+------------------+-----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------+ - -Transactions which allow to perform next boxes transitions - -+------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| Transaction name | Input parameters | Input parameters purpose | Output boxes | Output boxes purpose | -+==============================+==============================================================+===========================================================================================================================================+====================+=====================================================================================================================+ -| Car creation transaction | Regular Box | For paying fee | Car Box | Wanted new Car Box | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | Fee value | How much fee will be paid for the transaction | Regular Box | Change for fee | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | Car proposition | Owner car proposition as PublicKey25519Proposition | | | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | Vehicle identification number and any other car related data | Identification of the new car | | | -+------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| Car sell Order transaction | Car Box | Box which identifies a car for selling, initial car box will be opened and no longer is valid, thus in any case new Car Box shall be created | Car sell order Box | Representation of car in sell state, also contains additional information like seller coin box proposition address | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | Seller proposition for coin box | Where money will be sent to | | | -+------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| Car buying order transaction | Car sell order Box | Identify car for selling, contains seller coin box proposition address | Car box | New owner car box, with buyer proposition address | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | Payment regular box id | Id of box with money | Regular Box | New coin box which could be opened by seller which contains coins for selling car | -| +--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ -| | buyerProposition | Buyer proposition where money shall be sent | | | -+------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+--------------------+---------------------------------------------------------------------------------------------------------------------+ +User stories: +############# -Car registry implementation -*************************** +1 +**Q: I want to add my car to a Car Registry Sidechain.** -First of all we need to define new boxes. -As described before, a Car Box is a non-coin box. As defined before we need Car Box Data class as well for describing custom data. So we need to define CarBox and CarBoxData as separate classes for setting proper way to serialization/deserialization. +*A:* Create a new Car Entry Box, that contains car identification information (Unique can identifier, VIN, manufactures, model, year, registration number), and certificate. Proposition in this box is my public key in this Sidechain. When I create box Sidechain should check car identification information and certificate to be unique in this Sidechain. -So overall next classes will be created: +2 +**Q: I want to create sell order to sell my car using Car Registry Sidechain.** - :: - - public class CarBox extends AbstractNoncedBox - - :: - - public class CarBoxSerializer implements BoxSerializer +*A:* I create a new Car Sell Order Box, that contains the price in coins and information from the Car Entry Box. So cars can exist in the Sidechain as a Car Entry Box or as a Car Sell Order, but not both at the same time. Also, this box contains the buyer’s public key. When I create a sell order Sidechain should check if there is no other active sell order with this Car Entry Box. Current Sell Order consists of the same information that consists of the Car Entry Box plus description. - :: - - public class CarBoxData extends AbstractNoncedBoxData +3 +**Q: I want to see all available Sell orders in Sidechain** - :: - - public class CarSellOrder extends AbstractNoncedBox +*A:* Have additional storage, which is managed by ApplicationState and stores all Car Sell Orders. All these orders can be retrieved using the new HTTP API call. - :: - - public class CarSellOrderSerializer implements BoxSerializer - - :: - - public class CarSellOrderData extends AbstractNoncedBoxData - - :: - - public class CarSellOrderDataSerializer implements NoncedBoxDataSerializer +4 +**Q: I want to accept a sell order and buy the car.** -Implementation of CarBoxData -**************************** - - CarBoxData is implemented according to the description from “Custom Box Data Creation” chapter as public class CarBoxData extends AbstractNoncedBoxData with custom data as: +*A:* By accepting sell order I create a new transaction in the Sidechain, which creates a new Car Entry Box with my public key as proposition and transfers coins amount from me to the previous car owner. + +5 +**Q: I want to cancel my Car Sell Order.** + +*A:* I create a new transaction, that contains Car Sell Order as input and Car Entry Box with my public key as proposition as output. + +6. +**Q: I want to see my car entry boxes and car sell orders related to me (both created by me and proposed to me).** + +*A:* Implement new storage that will be managed by the application state to store this information. Implement a new HTTP API, that contains a new method to get this information. + +So, the starting point of the development process is the data representation. A car is an example of a non-coin box because it represents some entity, but not money. Another example of a non-coin box is a car that is selling. We need another box for a selling car because a common car box doesn't have additional data like sale price, seller proposition address, etc. For the money representation standard Regular Box is used (Regular box is coin box), that box is provided by SDK. Besides new entities CarBox and CarSellOrder we also need to define a way for creating/destroying those new entities. For that purpose new transactions shall be defined: transaction for creating a new car, transaction which moves CarBox to CarSellOrder, transaction which declares car selling, i.e. moving CarSellOrder to the new CarBox. All created transactions are not put into the memory pool automatically, so a raw transaction in hex representation shall be put by /transaction/sendTransaction API request. In summary, we will add the next car boxes and transactions: + ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Entity name | Entity description | Entity fields | ++=====================+=======================================================================================================================================================================================================================+=====================================================================================================================================================================================================================+ +| CarBox | Box which contains car box data, which could be stored and operated in Sidechain | boxData -- contains car box data | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CarBoxData | Description of the car by using defined properties | vin -- vehicle identification number which contains unique identification number of the car | +| | | year -- vehicle year production | +| | | model -- car model | +| | | color -- car color | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CarSellOrderBox | Box which contains car sell order data, which could be stored and operated in Sidechain. | boxData -- contains car sell order data | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CarSellOrderBoxData | Description of the car which is in sell status. That box data contains a special type of proposition SellOrderProposition. That proposition allows us to spent the box in two different ways: by seller and by buyer | vin -- vehicle identification number which contains unique identification number of the car | +| | | year -- vehicle year production | +| | | model -- car model | +| | | color -- car color | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CarSellOrderInfo | Information about car’s selling as well as proof of a current car owner. Used in transaction processing. | carBoxToOpen -- car box for start selling | +| | | proof -- proof for open initial car box | +| | | price -- selling price | +| | | buyerProposition -- current implementation expect to have the specific buyer which had been found off chain. Thus during creation of car sell order we already know buyer and shall put his future car proposition | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CarBuyOrderInfo | Data required for buying a car or recall a car sell order. Used in transaction processing. | carSellOrderBoxToOpen -- Car sell order box to be open | +| | | proof -- specific proof of type SellOrderSpendingProof | +| | | for confirming buying of the car or recall car sell order | ++---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Special proposition and proof: +############################## + + a) **SellOrderProposition** Standard proposition only contains one public key, i.e. only one specific secret key could open that proposition. + However, for a sell order we need a way to open and spend the box in two different ways, so we need to specify a additional proposition/proof. + SellOrderProposition contains two public keys: ``ownerPublicKeyBytes`` and ``buyerPublicKeyBytes``. So the seller or buyer private keys could open that proposition. + | + b) **SellOrderSpendingProof** The proof that allows us to open and spend ``CarSellOrderBox`` in two different ways: opened by the buyer and thus buy the car or opened by the seller and thus recall car sell order. Such proof creation requires two different API calls but as a result, in both cases, we will have the same type of transaction with the same proof type. + + +Transactions: +############# + +AbstractRegularTransaction +************************** + +Base custom transaction, all other custom transactions extend this base transaction. + + *Input parameters are:* + + ``inputRegularBoxIds`` - list of regular boxes for payments like fee and car buying + ``inputRegularBoxProofs`` - appropriate list of proofs for box opening for each regular box in ``inputRegularBoxIds`` + ``outputRegularBoxesData`` - list of output regular boxes, used as the change from paying a fee, as well as a new regular box for payment for the car. + ``fee`` - transaction fee + ``timestamp`` - transaction timestamp + + *Output boxes:* + + Regular Boxes created by change or car payment + +CarDeclarationTransaction +************************* + +Transaction for declaring a car in the Sidechain, this transaction extends ``AbstractRegularTransaction`` thus some base functionality already is implemented. + + *Input parameters are:* + + ``inputRegularBoxIds`` -- list of regular boxes for payments like fee and car buying + ``inputRegularBoxProofs`` -- appropriate list of proofs for box opening for each regular box in inputRegularBoxIds + ``outputRegularBoxesData`` -- list of output regular boxes, used as change from paying a fee, as well as a new regular box for car payment. + ``fee`` -- transaction fee + ``timestamp`` -- transaction timestamp + ``outputCarBoxData`` -- box data which contains information about a new car. + + *Output boxes:* + + New CarBox with new declared car + +SellCarTransaction +****************** + +Transaction for starting selling of the car. + + *Input parameters are:* + + ``inputRegularBoxIds`` - list of regular boxes for payments like fee and car buying + ``inputRegularBoxProofs`` - appropriate list of proofs for box opening for each regular box in inputRegularBoxIds + ``outputRegularBoxesData`` - list of output regular boxes, used as change from paying fee, as well as new regular box for payment for car. + ``fee`` -- transaction fee + ``timestamp`` - transaction timestamp + ``carSellOrderInfo`` - information about car selling, including such information as car description and specific proposition ``SellOrderProposition``. + + *Output boxes:* + + CarSellOrderBox which represents the car to be sold, that box could be opened by the initial car owner or specified buyer in case if buyer buys that car. + +BuyCarTransaction +***************** + +This transaction allows us to buy a car or recall a car sell order. + + *Input parameters are:* + + ``inputRegularBoxIds`` - list of regular boxes for payments like fee and purchasing the car + ``inputRegularBoxProofs`` - appropriate list of proofs for box opening for each regular box in inputRegularBoxIds + ``outputRegularBoxesData`` - list of output regular boxes, used as change from paying fee, as well as a new regular box for payment for the car. + ``fee`` - transaction fee + ``timestamp`` - transaction timestamp + ``carBuyOrderInfo`` - information for buy car or recall car sell order. + + *Output boxes:* + + Two possible outputs are possible. In the case of buying car: new CarBox with new owner, new Regular box with a value declared in carBuyOrderInfo for former owner of the Car. + +Car registry implementation +########################### + +First of all we need to define new boxes. +As described before, a Car Box is a non-coin box. As defined before we need Car Box Data class as well for describing custom data. So we need to define CarBox and CarBoxData as separate classes for setting proper way to serialization/deserialization. + +Implementation of CarBoxData: +***************************** + +CarBoxData is implemented according description from ``Custom Box Data Creation`` section as ``public class CarBoxData extends AbstractNoncedBoxData`` with custom data as: :: @@ -113,302 +178,315 @@ Implementation of CarBoxData private final int year; private final String model; private final String color; - private final String description; - public byte[] bytes() { - return Bytes.concat( - proposition().bytes(), - Longs.toByteArray(value()), - Ints.toByteArray(year), - Ints.toByteArray(model.getBytes().length), - model.getBytes(), - Ints.toByteArray(color.getBytes().length), - color.getBytes(), - Ints.toByteArray(description.getBytes().length), - description.getBytes(), - vin.toByteArray() - ); - } +Few comments about implementation: -1. Serialization is implemented by the SDK developer, as described before, shall include proposition and value into serialization. Ordering is not important. -2. CarBoxData shall have a value parameter as a Scorex limitation, but in our business logic CarBoxData does not use that data at all because each car is unique and doesn't have any inherent value. Thus value is hidden, i.e. value is not present in the constructor parameter and just set by default to “1” in the class constructor. -3. public byte[] customFieldsHash() shall be implemented because we introduce some new custom data. + 1. Special marker ``@JsonView(Views.Default.class)`` are used during class declaration, that annotation allows SDK core do proper JSON serialization. + 2. Serialization is implemented in ``public byte[] bytes()`` method as well as parsing implemented in ``public static CarBoxData parseBytes(byte[] bytes)`` method. SDK developer, as described before, shall include the proposition and value into serialization/deserialization. Order doesn't matter. + 3. ``CarBoxData`` shall have a value parameter as a Scorex limitation, but in our business logic CarBoxData does not use that data at all because each car is unique and doesn't have any inherent value. Thus value is hidden, i.e. value is not present in the constructor parameter and just set by default to “1” in the class constructor. + 4. ``public byte[] customFieldsHash()`` shall be implemented because we introduce some new custom data. + +Implementation of CarBoxDataSerializer: +*************************************** -Implementation of CarBoxDataSerializer -************************************** +``CarBoxDataSerializer`` is implemented according to the description from ``Custom Box Data Serializer Creation`` section as ``public class CarBoxDataSerializer implements NoncedBoxDataSerializer``. Nothing special to note about. -CarBoxDataSerializer is implemented according to the description from “Custom Box Data Serializer Creation” chapter as -public class CarBoxDataSerializer implements NoncedBoxDataSerializer. +Implementation of CarBox: +************************* -Implementation of CarBox -************************ + ``CarBox`` is implemented according to description from ``Custom Box Class creation`` section as ``public class CarBox extends AbstractNoncedBox`` -CarBox is implemented according to the description from “Custom Box Class creation” chapter as -public class CarBox extends AbstractNoncedBox Few comments about implementation: - 1. A long nonce whould be included as a part of serialization, thus serialization is implemented in next way: - + 1. As a serialization part SDK developer shall include ``long nonce`` as a part of serialization, thus serialization is implemented in the following way: + + :: + public byte[] bytes() + { + return Bytes.concat( + Longs.toByteArray(nonce), + CarBoxDataSerializer.getSerializer().toBytes(boxData) + ); + } + + 2. ``CarBox`` defines his own unique id by implementation of the function ``public byte boxTypeId()``. Similar function is defined in ``CarBoxData`` but it is a different ids despite value returned in ``CarBox`` and ``CarBoxData`` is the same. + +Implementation of CarBoxSerializer: +*********************************** + +CarBoxSerializer is implemented according to the description from “Custom Box Data Serializer Creation” section as +``public class CarBoxSerializer implements BoxSerializer``. Nothing special to note about. + +Implementation of SellOrderProposition +************************************** + +``SellOrderProposition`` implemented as ``public final class SellOrderProposition implements ProofOfKnowledgeProposition`` +Nothing special about implementation besides the fact that that proposition contains two public keys, thus that proposition could be opened by two different keys. + +Implementation of SellOrderPropositionSerializer +************************************************ + +``SellOrderPropositionSerializer`` implemented as ``public final class SellOrderPropositionSerializer implements PropositionSerializer`` +Nothing special about implementation + +Implementation of SellOrderSpendingProof +**************************************** + +``SellOrderSpendingProof implemented as extends AbstractSignature25519`` + +Few comments about implementation: Information about proof type is defined by the result of method boolean isSeller(). For example an implementation of method isValid uses that flag: + :: - public byte[] bytes() - { - return Bytes.concat( - Longs.toByteArray(nonce), - CarBoxDataSerializer.getSerializer().toBytes(boxData) - ); + + public boolean isValid(SellOrderProposition proposition, byte[] message) { + if(isSeller) { + // Car seller wants to discard selling. + return Ed25519.verify(signatureBytes, message, proposition.getOwnerPublicKeyBytes()); + } else { + // Specific buyer wants to buy the car. + return Ed25519.verify(signatureBytes, message, proposition.getBuyerPublicKeyBytes()); } - - - 2. CarBox defines it's own unique id by implementation of the function public byte boxTypeId(). Similar function is defined in CarBoxData but it is a different id despite value returned in CarBox and CarBoxData is the same. - + } + + +Implementation of CarSellOrderBoxData +************************************* -Implementation of CarBoxSerializer -********************************** +CarSellOrderBoxData is implemented according description from “Custom Box Data Creation” chapter as public class CarSellOrderData extends AbstractNoncedBoxData with custom data as: +private final String vin; +private final int year; +private final String model; +private final String color; -CarBoxSerializer is implemented according to the description from “Custom Box Data Serializer Creation” chapter as -public class CarBoxSerializer implements BoxSerializer. +Few comments about implementation: +Proposition and value shall be included in serialization as it done in CarBoxData +Id of that box data could be different than in CarBoxData +CarSellOrderBoxData uses custom proposition type, thus proposition field have SellOrderProposition type -Implementation of CarSellOrderData -********************************** -CarSellOrderData is implemented according description from “Custom Box Data Creation” chapter as public class CarSellOrderData extends AbstractNoncedBoxData with custom data as: -private final PublicKey25519Proposition sellerProposition; -private final BigInteger vin; -Comments about implementation: - 1. Proposition and value shall be included in serialization as it done in CarBoxData - 2. Id of that box data shall different than in CarBoxData - -Implementation of CarSellOrderDataSerializer -******************************************** +Implementation of CarSellOrderBoxDataSerializer +*********************************************** CarSellOrderDataSerializer is implemented according to the description from “Custom Box Data Serializer Creation” chapter as -public class CarSellOrderDataSerializer implements NoncedBoxDataSerializer. +public class CarSellOrderBoxDataSerializer implements NoncedBoxDataSerializer. +Nothing special to note about. -Implementation of CarSellOrder -****************************** +Implementation of CarSellOrderBox +********************************* CarSellorder is implemented according to description from “Custom Box Class creation” chapter as -public class CarSellOrder extends AbstractNoncedBox +public final class CarSellOrderBox extends AbstractNoncedBox +Nothing special about implementation. -Extend API by creating new transactions Car creation transaction and Car sell Order transaction -*********************************************************************************************** -For our purpose we need to define two transaction's, a Car creation transaction and a Car sell Order transaction according to the custom API extensionas below: -a) Create a new class CarApi which extends ApplicationApiGroup class, add that new class to Route by it in SimpleAppModule, like described in Custom API manual. In our case it is done in CarRegistryAppModule by +AbstractRegularTransaction +************************** - * Creating customApiGroups as a list of custom API Groups: - * List customApiGroups = new ArrayList<>(); - * Adding created CarApi into customApiGroups: - customApiGroups.add(new CarApi()); - * Binding that custom api group via dependency injection: - :: - - bind(new TypeLiteral> () {}) - .annotatedWith(Names.named("CustomApiGroups")) - .toInstance(customApiGroups); - -b) Define Car creation transaction. - - 1. Defining request class/JSON request body - As input for the transaction we expect: - Regular box id as input for paying fee; - Fee value; - Proposition address which will be recognized as a Car Proposition; - Vehicle identification number of car. So next request class shall be created: - - :: - - public static class CreateCarBoxRequest { - private BigInteger vin; - private int year; - private String model; - private String color; - private String description; - private PublicKey25519Proposition carProposition; +AbstractRegularTransaction is implemented as public abstract class AbstractRegularTransaction extends SidechainTransaction> - private int fee; - private String boxId; +Basic functionality is implemented for building required unlockers for input Regular boxes as well as returning a list of output Regular boxes according to input parameter outputRegularBoxesData. Also basic transaction semantic validity is checked here. - public BigInteger getVin() { - return vin; - } - public void setVin(String vin) { - this.vin = new BigInteger(vin); - } +CarDeclarationTransaction +************************* +CarDeclarationTransaction extends previously declared AbstractRegularTransaction in next way: public final class CarDeclarationTransaction extends AbstractRegularTransaction +newBoxes() -- new box with newly created car shall be added as well, thus that function shall be overridden as well for adding new CarBox additional to regular boxes. - public int getYear() { - return year; - } +SellCarTransaction +****************** - public void setYear(int year) { - this.year = year; - } +SellCarTransaction extends previously declared AbstractRegularTransaction in next way: public final class SellCarTransaction extends AbstractRegularTransaction +Similar to CarDeclarationTransaction, newBoxes() function shall also return a new specific box. In our case that new box is CarSellOrderBox. Also due we have specific box to open (CarBox), we also need to add unlocker for CarBox, so unlocker for that CarBox had been added in public List> unlockers() - public String getModel() { - return model; - } +BuyCarTransaction +***************** - public void setModel(String model) { - this.model = model; - } +Few comments about implementation: +During creation of unlockers in function unlockers() we need to also create a specific unlocker for opening a car sell order. Another newBoxes() function has a bit specific implementation. That function forces to create a new RegularBox as payment for a car in case the car has been sold. Anyway, a new Car box also shall be created according to information in carBuyOrderInfo. - public String getColor() { - return color; - } +Extend API: +*********** - public void setColor(String color) { - this.color = color; - } + Create a new class CarApi which extends ApplicationApiGroup class, add that new class to Route by it in SimpleAppModule, like described in Custom API manual. In our case it is done in CarRegistryAppModule by +Creating customApiGroups as a list of custom API Groups: +List customApiGroups = new ArrayList<>(); - public String getDescription() { - return description; - } +Adding created CarApi into customApiGroups: + customApiGroups.add(new CarApi()); - public void setDescription(String description) { - this.description = description; - } +Binding that custom api group via dependency injection: +bind(new TypeLiteral> () {}) + .annotatedWith(Names.named("CustomApiGroups")) + .toInstance(customApiGroups); - public PublicKey25519Proposition getCarProposition() { - return carProposition; - } - public void setCarProposition(String propositionHexBytes) { - byte[] propositionBytes = BytesUtils.fromHexString(propositionHexBytes); - carProposition = new PublicKey25519Proposition(propositionBytes); - } +Define Car creation transaction. +Defining request class/JSON request body +As input for the transaction we expected: +Regular box id as input for paying fee; +Fee value; +Proposition address which will be recognized as a Car Proposition; +Vehicle identification number of car. So next request class shall be created: +public class CreateCarBoxRequest { + public String vin; + public int year; + public String model; + public String color; + public String proposition; // hex representation of public key proposition + public long fee; - public int getFee() { - return fee; - } + // Setters to let Akka jackson JSON library to automatically deserialize the request body. - public void setFee(int fee) { - this.fee = fee; - } + public void setVin(String vin) { + this.vin = vin; + } - public String getBoxId() { - return boxId; - } + public void setYear(int year) { + this.year = year; + } - public void setBoxId(String boxId) { - this.boxId = boxId; - } - } + public void setModel(String model) { + this.model = model; + } -Request class should have appropriate setters and getters for all class members, also class members' names define structure for related JSON structure according to the jackson library so JSON structure is expected: + public void setColor(String color) { + this.color = color; + } - :: - - { - "vin": "30124", - “year”: 1984, - “model”: “Lamborghini”“ color”: ”deep black”“ description”: ”best car in the world” "carProposition": "a5b10622d70f094b7276e04608d97c7c699c8700164f78e16fe5e8082f4bb2ac", - "fee": 1, - "boxId": "d59f80b39d24716b4c9a54cfed4bff8e6f76597a7b11761d0d8b7b27ddf8bd3c" - } + public void setProposition(String proposition) { + this.proposition = proposition; + } -Points to note: setter input parameter could have different type than set class member, it allow's us to do all necessary conversation in setters; byte data is represented initially as a hex string, which converted to bytes by BytesUtils.fromHexString() function. + public void setFee(long fee) { + this.fee = fee; + } +} -2. Define response for Car creation transaction. The result of transaction shall be defined by implementing SuccessResponse interface with class members which will be returned as API response, all members should have properly settters and getters, also response class shall have proper annotation @JsonView(Views.Default.class) thus jackson library is able correctly represent response class in JSON format. In our case we expect to return transaction bytes, so response class is next: - :: - - @JsonView(Views.Default.class) - class CarResponse implements SuccessResponse { - private final String createCarTxBytes; +Request class shall have appropriate setters and getters for all class members, also class members' names define structure for related JSON structure according jackson library so next JSON structure is expected to be set: +{ + "vin":"30124", + “year”:1984, + “model”: “Lamborghini” + “color”:”deep black” +"carProposition":"a5b10622d70f094b7276e04608d97c7c699c8700164f78e16fe5e8082f4bb2ac", + "fee": 1, + "boxId": "d59f80b39d24716b4c9a54cfed4bff8e6f76597a7b11761d0d8b7b27ddf8bd3c" +} +Few interesting moments: setter’s input parameter could have differ type than set class member, it’s allow us to do all necessary conversation in setters. - public CarResponse(String createCarTxBytes) { - this.createCarTxBytes = createCarTxBytes; - } +Define response for Car creation transaction, result of transaction shall be defined by implementing SuccessResponse interface with class members which shall be returned as API response, all members shall have properly set getters, also response class shall have proper annotation @JsonView(Views.Default.class) thus jackson library is able correctly represent response class in JSON format. In our case we expect to return transaction bytes, so response class is next: - public String carTxBytes() { - return createCarTxBytes; - } +@JsonView(Views.Default.class) +class TxResponse implements SuccessResponse { + public String transactionBytes; - public String getCreateCarTxBytes() { - return createCarTxBytes; - } - } + public TxResponse(String transactionBytes) { + this.transactionBytes = transactionBytes; + } +} -3. Define Car creation transaction - :: - - private ApiResponse createCar(SidechainNodeView view, CreateCarBoxRequest ent) +Define Car creation transaction itself +private ApiResponse createCar(SidechainNodeView view, CreateCarBoxRequest ent) As a first parameter we pass reference to SidechainNodeView, second reference is previously defined class on step 1 for representation of JSON request. -During transaction creation we need to do next: - - * check is input box secret is present in our wallet at all - * check if enough coins are stored in that box to pay fee - * calculate fee for change - * create RegularBoxData for change for fee - * create new CarBoxData according JSON request data - * create inputs from input box and outputs RegularBoxData for change and new CarBoxData - * calculate additional data like timestamp - * get list of fake proof which are required to build message to be signed: List fakeProofs = Collections.nCopies(inputIds.size(), null); - * build transaction bytes to be signed instead of real proof put some fake proof into from the previous step. For transaction creation a special factory shall be used. Access to that factory could be achieved by call getSidechainCoreTransactionFactory()function: - SidechainCoreTransaction unsignedTransaction = - getSidechainCoreTransactionFactory().create(inputIds, outputs, fakeProofs, ent.fee, timestamp); - byte[] messageToSign = unsignedTransaction.messageToSign(); - * create proof by sign transaction by private key of input box - * create new transaction - * add to the CarResponse created transaction bytes - -4. Define request for Car sell order transaction CreateCarSellOrderRequest similar as it was done for Car creation transaction request - -5. Define response for Car sell order transaction CreateCarSellOrderResponce as it was done for Car creation transaction response - -6. Define Car Sell order transaction - private ApiResponse createCarSellOrder(SidechainNodeView view, CreateCarSellOrderRequest ent) - Required actions are similar as it was done for Create Car transaction, but we don’t need to worry about fee, i.e. fee is set as 0. Main idea is a moving Car Box into CarSellOrderBox - -7. Define Car sell order response -As a result of Car sell order we want to get hex byte representation of that transaction -8. Define request class for accepting Car Sell Order Transaction, with input: -String carSellOrderId; -String paymentRegularBoxId; -PublicKey25519Proposition buyerProposition; -9. Define response class for CarSellOrder transaction -Response shall contains hex representation of transaction bytes, thus response class are next: - :: - @JsonView(Views.Default.class) - class AcceptCarSellOrderResponce implements SuccessResponse { - private final String acceptedCarSellOrderTxBytes; - - public AcceptCarSellOrderResponce(String acceptedCarSellOrderTxBytes) { - this.acceptedCarSellOrderTxBytes = acceptedCarSellOrderTxBytes; - } - - public String acceptedCarSellOrderTxBytes() { - return acceptedCarSellOrderTxBytes; - } - - public String getAcceptedCarSellOrderTxBytes() { - return acceptedCarSellOrderTxBytes; - } - } - -10. Create AcceptCarSellorder transaction +C. Define request for Car sell order transaction CreateCarSellOrderRequest similar as it was done for Car creation transaction request +Define request class for Car sell order transaction CreateCarSellOrderRequest as it was done for Car creation transaction request: +public class CreateCarSellOrderRequest { + public String carBoxId; // hex representation of box id + public String buyerProposition; // hex representation of public key proposition + public long sellPrice; + public long fee; + + // Setters to let Akka jackson JSON library to automatically deserialize the request body. + + public void setCarBoxId(String carBoxId) { + this.carBoxId = carBoxId; + } + + public void setBuyerProposition(String buyerProposition) { + this.buyerProposition = buyerProposition; + } + + public void setSellPrice(long sellPrice) { + this.sellPrice = sellPrice; + } + public void setFee(int fee) { + this.fee = fee; + } +} +Define Car Sell order transaction itself +private ApiResponse createCarSellOrder(SidechainNodeView view, CreateCarSellOrderRequest ent) +Required actions are similar as it was done for Create Car transaction. Main idea is a moving Car Box into CarSellOrderBox + +Define Car sell order response +As a result of Car sell order we could still use TxResponse + + + +D. Create AcceptCarSellorder transaction +Specify request as +public class SpendCarSellOrderRequest { + public String carSellOrderId; // hex representation of box id + public long fee; + + // Setters to let Akka jackson JSON library to automatically deserialize the request body. + + public void setCarSellOrderId(String carSellOrderId) { + this.carSellOrderId = carSellOrderId; + } + + public void setFee(long fee) { + this.fee = fee; + } +} +Specify acceptCarSellOrder transaction itself +As a result we still could use TxResponse class +Important part is creation proof for BuyCarTransaction, because we accept car buying then we shall form proof with defining that we buy car: + SellOrderSpendingProof buyerProof = new SellOrderSpendingProof( + buyerSecretOption.get().sign(messageToSign).bytes(), + isSeller +); +Where isSeller is false. + +E. Create cancelCarSellOrder transaction +Specify cancel request as +public class SpendCarSellOrderRequest { + public String carSellOrderId; // hex representation of box id + public long fee; + + // Setters to let Akka jackson JSON library to automatically deserialize the request body. + + public void setCarSellOrderId(String carSellOrderId) { + this.carSellOrderId = carSellOrderId; + } + + public void setFee(long fee) { + this.fee = fee; + } +} +Specify transaction itself. Because we recall our sell order then isSeller parameter during transaction creation is set to false. +