[pybitshares/uptick] How to add new on-chain featuressteemCreated with Sketch.

in #bitshares7 years ago

This post serves as a quick guide into the underlying functionality of pybitshares and uptick.

In this tutorial, we add a new feature that allows you to create a new committee member that can then be voted by BTS hodlers.

1. Implement operation

This step sets up a new class that tells the library how that particular operation is called and what it does.
The definition of those are burried deeply into bitshares-core. In this case, we take a closer look into porotocol/committee-member.hpp, identify the struct's members and add them in the same order to pybitshares:

   struct committee_member_create_operation : public base_operation
   {
      struct fee_parameters_type { uint64_t fee = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION; };

      asset                                 fee;
      /// The account which owns the committee_member. This account pays the fee for this operation.
      account_id_type                       committee_member_account;
      string                                url;

      account_id_type fee_payer()const { return committee_member_account; }
      void            validate()const;
};

For python-bitshares:

class Committee_member_create(GrapheneObject):
    def __init__(self, *args, **kwargs):
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('fee', Asset(kwargs["fee"])),
                ('committee_member_account', ObjectId(kwargs["committee_member_account"], "account")),
                ('url', String(kwargs["url"])),
]))

What is important here is that the class name is identical to the operations listed here, except that the first letter is capital.

commit

2. Test operation

Now we go further and test the new operation against the cli_wallet. For that, we start a cli wallet and expose the cli_wallet's API locally at port 8092. We then install the new operation into the compareConstructedTX() call like this.

When calling python3 tests/test_transactions.py, we now get

{'expiration': '2016-04-06T08:29:27',
 'extensions': [],
 'operations': [[29,
                 {'committee_member_account': '1.2.0',
                  'fee': {'amount': 0, 'asset_id': '1.3.0'},
                  'url': 'foobar'}]],
 'ref_block_num': 34294,
 'ref_block_prefix': 3707022213,
 'signatures': ['2035e1564b63c8fe55c0ba176044468ffbddffe0241792625de8365e55522f2488261ac0dd2e22aca4aeb6da48b0773837e89c4f36cfd86df1eb78119fe8a2d21e']}
================================================================================
soll: f68585abf4dce7c80457011d0000000000000000000006666f6f6261720001
ist:  f68585abf4dce7c80457011d0000000000000000000006666f6f6261720001
True

Which compares the serialization of cli-wallet with pybitshares.
In this case, it all looks fine and we add a unit test like this

Since we initially don't know the output to compare with, we can use self.doIt(True) to let the unittest provide the string we want to compare it with later on.

We execute the unit test with

 python3 -m unittest tests.test_transactions.Testcases.test_committee_create 

The outputed string is then stored in self.cm so that the unittest succeeeds afterwards.

3. Expose the functionality in bitshares.py

We now write an API into bitshares.py to expose the feature for easier usage:

https://github.com/xeroc/python-bitshares/blob/8a556c0031186abe3084d3e44e3dd38bbe40f0cb/bitshares/bitshares.py#L1407-L1431

Here, all we do is make sure we use some account (default if not present), make sure the account exists, construct the operation and forward it for signing through finalizeOp. This signs it with the active key of account if the key is present in the wallet.

4. Integrate into uptick

uptick is a command line tool that makes heavy use of pybitshares and python-click.
using the new feature is easy as all we need to do is add a new method like here

@main.command()
@click.pass_context
@onlineChain
@click.argument('url', type=str)
@click.option(
    "--account",
    help="Account that takes this action",
    default=config["default_account"],
    type=str)
@unlockWallet
def createcommittee(ctx, url, account):
    """ Setup a committee account for your account
    """
    pprint(ctx.bitshares.create_committee_member(
        url,
        account=account
))

I hope this makes it clear how easy it is to use python bitshares and uptick.
If you decide to take on some of the missing operations, please feel free to send pull requests my way.

Sort:  

class Committee_member_create(GrapheneObject):

Is there a specific reason why pybitshares break the python convention on class names? This should be CommitteeMemberCreate for example. :)

Yes, the reason is that I don't want the developer to manually provide the OperationID for that operation and instead obtain it automatically from the list of operation ids by using the operation name:
https://github.com/xeroc/python-graphenelib/blob/master/graphenebase/objects.py#L19-L38

Thanks for sharing this, it's quite helpful

Hey @xeroc , this is great information to us , thanks for the enlighten.

thanks for the job we are waiting for your next welfare .

Why are you powering up 100%??

brilliant & exceptional!

Congratulations @xeroc! You have received a personal award!

2 Years on Steemit
Click on the badge to view your own Board of Honor on SteemitBoard.

Upvote this notificationto to help all Steemit users. Learn why here!

Cool stuff dude! I'm not really good with coding, I tried two different times, but hey its still really spectacular!

Great info . It is always nice to get fresh intel regarding pybitshares. Thanks

post.JPG

Congratulation

Today 2 years ago you joined SteemIt
Thank you, for making SteemIt great and Steem on for more years to come!

(You are being celebrated here)