The order example demonstrates how you can create an order and add user command. This example consists of one python script /demoOreder.py and manifest file /manifest.json.
from DAP.Core import logIt
from DAP.Crypto import HashFast, Algo, CryptoKeyType
from CellFrame.Network import Net, ServiceOrder, ServiceOrderDirection, ServiceUID, ServicePriceUnitUID
from CellFrame import AppCliServer
import time
from datetime import datetime, timedelta
"""This function is designed to get a string representation of the values that are in the order. """
def infoOrder(order):
reply = "Order: \n"
reply += "\tVersion:" + str(order.version)+"\n"
reply += "\tUID: " + str(order.uid) + "\n"
reply += "\tDirection: " + str(order.direction) + "\n"
reply += "\tNode addr: " + str(order.nodeAddr) + "\n"
reply += "\tCond hash: " + str(order.condHash) + "\n"
reply += "\tPrice unit: " + str(order.priceUnit) + "\n"
created = datetime.fromtimestamp(order.tsCreated)
reply += "\tCreated: " + str(created) + "\n"
expires = datetime.fromtimestamp(order.tsExpires)
reply += "\tExpires: " + str(expires) + "\n"
reply += "\tSrv price: " + str(order.srvPrice) + "\n"
reply += "\tSrv price ticker: " + order.srvPriceTicker + "\n"
reply += "\textSignSize:" + str(order.extSize) + "\n"
reply += "\tSignature:\n"
sign = order.extSign
if sign is None:
reply += "Signature none"
else:
type = sign.type
pkey = sign.pkey
pkey_type = pkey.type
# pkey_hash = pkey.hash
pkey_size = pkey.size
pkey_dict = {
'type': str(pkey_type),
'size': pkey_size
}
pkey_hash = sign.pkeyHash
sig_dict = {
'type': str(sign.type),
'pkey': pkey_dict,
'pkey_hash': str(pkey_hash),
'size': str(sign.size)
}
reply += str(sig_dict)
# reply += "\Signs:" + str(order.ext) + "\n"
return reply
def pwoCMD(argv, indexStrReply):
if (len(argv) == 5):
net = Net.byName(argv[2])
if argv[3] == "find":
order = ServiceOrder.find(net, argv[4])
reply = ""
if order is None:
reply = "Order with hash "+argv[4]+" not fined."
else:
reply = "Order: \n"
order_reply = infoOrder(order)
reply += order_reply
AppCliServer.setReplyText(reply, indexStrReply)
elif argv[3] == "del":
res = ServiceOrder.delete(net, argv[4])
AppCliServer.setReplyText("Result: "+str(res)+".", indexStrReply)
else:
AppCliServer.setReplyText("An unknown action is specified to be performerd on the order.", indexStrReply)
else:
AppCliServer.setReplyText("This command takes only four arguments.", indexStrReply)
"""
This function is a notifier, it is triggered when an order is created or deleted from GlobalDB.
It takes the following arguments as input
* op_code is responsible for the state of the pian order or deleted.
* group name in globalDB.
* the key by which the value is located (usually a hash).
* The data itself, in this case it is the order object
* the object that was set when setting the notifier, it can be a string, a number, a function, etc. In this case, it is a string.
"""
def order_notify(op_code, group, key, order, arg):
logIt.notice("Arg: "+arg)
logIt.notice("Notify: \n")
logIt.notice("op_code: "+op_code+"\n")
logIt.notice("group: "+group+"\n")
logIt.notice("key: "+key+"\n")
if order is not None:
logIt.notice(infoOrder(order))
else:
logIt.notice("No order.")
def init():
logIt.notice("Running plugin order")
net = Net.byName("kelvin-testnet")
# We add a notifier that will work when creating or deleting an order.
ServiceOrder.addNotify(net, order_notify, "This is the same line that will be printed out when the notifier "
"argument is printed. ")
# We receive and display information about the group where orders are stored, as well as about the nodelist.
gdb_group = ServiceOrder.getGdbGroup(net)
logIt.notice("Ordr in group: "+gdb_group)
node_list_group = ServiceOrder.getNodelistGroup(net)
logIt.notice("Node list group: "+node_list_group)
# Creating a new order
# Set the direction of the order and the UID of the service.
net_srv = ServiceUID(12345)
direction = ServiceOrderDirection.getDirSell()
# We get the address of the node.
node_addr = net.getCurAddr()
"""tx_cond - This should be the address of the conditional transaction, but it is not required to create an order.
But in the order that the service issues, it should be."""
# We set the price and units of measurement, for which you buy for this price.
price = 531
priceUnitUid = ServicePriceUnitUID.mb()
"""The key generation function accepts the type of the generated key, kex_buf,
the size of the generated key, and the seed phrase. """
key = Algo.generateNewKey(CryptoKeyType.DAP_ENC_KEY_TYPE_SIG_BLISS(), "SARON00151454_VDGTKHJFY", 512, " I SIMPKLE SEED STRING ")
# We determine the lifetime of the order, at the moment it is not used in the SDK.
dt_exp = datetime.now()
dt_delta = timedelta(days=30)
dt_exp += dt_delta
ts_expires = dt_exp.timestamp()
"""
With the help of this constructor, an order is created. The constructor takes the following parameters as input:
* Network object.
* Direction order
* Service UID.
* Node address.
* Hash of the conditional transaction in this case None.
* Price.
* Units of measure.
* A set of bytes, there can be any information in this case, the URL address.
* The key with which the order is signed.
"""
order = ServiceOrder(net, direction, net_srv, node_addr, None, price, priceUnitUid, "tCELL", ts_expires, "http://myvi.com/?QBS".encode('utf-8'), key)
# This function simply saves the order and returns its hash, by which the order can be found or deleted.
hash = order.save(net)
logIt.notice("HASH order:"+str(hash))
AppCliServer.cmdItemCreate("pwo", pwoCMD, "Example command for working with orders through the plugin",
"""
Arguments for command:
net <net> find <hash order>
net <net> del <hash order>
""")
return 0
{
"name": "demoOrder",
"version": "1.0",
"author": "DEMLABS (C) 2022",
"dependencies": [],
"description": "This is a plugin with examples for working with orders."
}
This /demoOrder.py script contains four functions: infoOrder
, pwoCMD
, order_notify
and init
.
The execution of the plugin starts with the init
. The pwoCMD
is a handler of an user's command. The order_notify
is a handler for adding an order. The infoOrder
is a formatter function.
The pwo user's command have a following format:
net <net> find <hash order>
or
net <net> del <hash order>
1. The plugin is initialized by the init
function:
def init():
2. The logIt.notice
function logs a message:
logIt.notice("Running plugin order")
3. In init()
function we are using the byName
static method of the Net
class to get an instance of the Net
object. The kelvin-testnet is a net name:
net = Net.byName("kelvin-testnet")
4. The addNotify
static method of the ServiceOrder
class is setting a callback function that is called when an order is added into the GDB:
ServiceOrder.addNotify(net, order_notify, "This is the same line that will be printed out when the notifier "
"argument is printed. ")
The net
argument is an instance of the Net
object and the order_notify
is a callback function name.
5. The getGdbGroup
static method of the ServiceOrder
class is getting a GDB group name of a network:
gdb_group = ServiceOrder.getGdbGroup(net)
The gdb_group
is a string.
6. Logging a message:
logIt.notice("Ordr in group: " + gdb_group)
7. The getNodelistGroup
static method of the ServiceOrder
class is getting a node list name:
node_list_group = ServiceOrder.getNodelistGroup(net)
The node_list_group
is a string
8. Logging a message:
logIt.notice("Node list group: " + node_list_group)
9. Creating an instance of ServiceUID
object using a constructor:
net_srv = ServiceUID(12345)
10. The getCurAddr
static method of the ServiceOrderDirection
class is creating an instance of a ServiceOrderDirection
object that that sets the direction of the order corresponding to sell.
direction = ServiceOrderDirection.getDirSell()
11. The getCurAddr
static method of the Net
class is getting a instance of a NodeAddr
object. It is a current address of net.
node_addr = net.getCurAddr()
12. Setting a price and a price unit:
price = 531
priceUnitUid = ServicePriceUnitUID.mb()
The mb
static method of the ServicePriceUnitUID
class is creating a megabytes unit.
13. Creating a new instance of a CryptoKey
object using the generateNewKey
static method of the Algo
class:
key = Algo.generateNewKey(CryptoKeyType.DAP_ENC_KEY_TYPE_SIG_BLISS(),
"SARON00151454_VDGTKHJFY",
512,
" I SIMPKLE SEED STRING ")
The DAP_ENC_KEY_TYPE_SIG_BLISS
static method of the CryptoKeyType
class is returning a BLISS key type."SARON00151454_VDGTKHJFY" is a key. 512 is a key size. The " I SIMPKLE SEED STRING " is a seed string.
14. Setting the expired date and time:
dt_exp = datetime.now()
dt_delta = timedelta(days=30)
dt_exp += dt_delta
ts_expires = dt_exp.timestamp()
The expired date is 30 days after the plugin is launched.
15. Creating an instance of a ServiceOrder
object using constructor:
order = ServiceOrder(net, direction, net_srv, node_addr, None, price, priceUnitUid, "tCELL", ts_expires, "http://myvi.com/?QBS".encode('utf-8'), key)
The "tCELL is a price ticker. The "http://myvi.com/?QBS" is a service URL.
16. Saving the order into the net using save
method of the ServiceOrder
object:
hash = order.save(net)
The hash
is a DAP.Crypto.HashFast
object.
17. Logging a message:
logIt.notice("HASH order:" + str(hash))
18. And at the end adding pwo user command:
AppCliServer.cmdItemCreate("pwo", pwoCMD, "Example command for working with orders through the plugin",
"""
Arguments for command:
net <net> find <hash order>
net <net> del <hash order>
""")
The "pwo" is a command name. The pwoCMD
is a name of callback function that is called when receiving a command from a client console. The next two arguments are a help strings.
19. Returning 0. This means that the plugin has been successfully initialized:
return 0
1. The pwoCMD
functions gets two arguments: argv
and indexStrReptly
. The argv
is a list that contains the command name and the arguments that the user specified when running the pwo command. The indexStrReply
argument is intended to respond to the user.
def pwoCMD(argv, indexStrReply):
2. Checking whether the user has specified five arnuments
if (len(argv) == 5):
3. Creating an instance of the Net
object using the byName
static method of the Net
class:
net = Net.byName(argv[2])
4. Checking the fifth argument, which can be either find or delete:
if argv[3] == "find":
5. The find
static method is finding and returning an instance of a ServiceOrder
object:
order = ServiceOrder.find(net, argv[4])
6. The reply
variable is used to format a response.
reply = ""
7. Depending on whether an order was found or not, a response is generated. If the order was found, the response is formed based infoOrder
function:
if order is None:
reply = "Order with hash "+argv[4]+" not fined."
else:
reply = "Order: \n"
order_reply = infoOrder(order)
reply += order_reply
8. The setReplyText
method of the AppCliServer
class sets the response to the user's command. The reply
is a string that will be sent to the client. The indexStrReply
is an argument from the pwoCMD
function.
AppCliServer.setReplyText(reply, indexStrReply)
9. If the user used the del subcommand then the order is deleted using a delete
method of the ServiceOrder
class:
elif argv[3] == "del":
res = ServiceOrder.delete(net, argv[4])
AppCliServer.setReplyText("Result: "+str(res)+".", indexStrReply)
10. If the user has entered an unknown command:
else:
AppCliServer.setReplyText("An unknown action is specified to be performerd on the order.", indexStrReply)
11. If the user has entered not four arguments:
else:
AppCliServer.setReplyText("This command takes only four arguments.", indexStrReply)
1. The order_notify
functions gets four arguments. The op_code
is a operation code, the group
is a GDB group name of a network, the key
is a key and the order
is added order:
def order_notify(op_code, group, key, order):
logIt.notice("Arg: "+arg)
logIt.notice("Notify: \n")
logIt.notice("op_code: "+op_code+"\n")
logIt.notice("group: "+group+"\n")
logIt.notice("key: "+key+"\n")
if order is not None:
logIt.notice(infoOrder(order))
else:
logIt.notice("No order.")
This function formatted a reply using attributes of the ServerOrder
and Sign
classes:
reply = "Order: \n"
reply += "\tVersion:" + str(order.version)+"\n"
reply += "\tUID: " + str(order.uid) + "\n"
reply += "\tDirection: " + str(order.direction) + "\n"
reply += "\tNode addr: " + str(order.nodeAddr) + "\n"
reply += "\tCond hash: " + str(order.condHash) + "\n"
reply += "\tPrice unit: " + str(order.priceUnit) + "\n"
created = datetime.fromtimestamp(order.tsCreated)
reply += "\tCreated: " + str(created) + "\n"
expires = datetime.fromtimestamp(order.tsExpires)
reply += "\tExpires: " + str(expires) + "\n"
reply += "\tSrv price: " + str(order.srvPrice) + "\n"
reply += "\tSrv price ticker: " + order.srvPriceTicker + "\n"
reply += "\textSignSize:" + str(order.extSize) + "\n"
reply += "\tSignature:\n"
sign = order.extSign
if sign is None:
reply += "Signature none"
else:
type = sign.type
pkey = sign.pkey
pkey_type = pkey.type
# pkey_hash = pkey.hash
pkey_size = pkey.size
pkey_dict = {
'type': str(pkey_type),
'size': pkey_size
}
pkey_hash = sign.pkeyHash
sig_dict = {
'type': str(sign.type),
'pkey': pkey_dict,
'pkey_hash': str(pkey_hash),
'size': str(sign.size)
}
reply += str(sig_dict)
# reply += "\Signs:" + str(order.ext) + "\n"
return reply