{"id":20272328,"url":"https://github.com/steemit/rcdemo","last_synced_at":"2025-04-11T04:41:55.588Z","repository":{"id":72308912,"uuid":"152484823","full_name":"steemit/rcdemo","owner":"steemit","description":null,"archived":false,"fork":false,"pushed_at":"2018-10-10T20:31:57.000Z","size":11,"stargazers_count":10,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-25T02:51:13.531Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steemit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-10T20:21:17.000Z","updated_at":"2022-02-12T00:44:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"942ba7e3-02f2-4633-9f52-9dd3611a2948","html_url":"https://github.com/steemit/rcdemo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Frcdemo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Frcdemo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Frcdemo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Frcdemo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steemit","download_url":"https://codeload.github.com/steemit/rcdemo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345281,"owners_count":21088242,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T12:42:54.547Z","updated_at":"2025-04-11T04:41:55.577Z","avatar_url":"https://github.com/steemit.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Resource Credit System developer guide\n\nThe goal of this guide is to demystify how resources and RC's work.  The intended audience is developers working on Steem user interfaces,\napplications, and client libraries.\n\n### Statelessness\n\nFirst of all, a word about statelessness.  A great deal of effort has gone into carefully separating stateful from stateless computations.\nThe reason for this is so that UI's and client libraries can execute stateless algorithms locally.  Local computation is always to be\npreferred to RPC-API for performance, stability, scalability and security.\n\nUnfortunately, client library support for RC algorithms is lacking.  This tutorial, and its accompanying script, are intended to\nprovide guidance to UI and client library maintainers about how to add support for the RC system.\n\n# The RC demo script\n\nTo get up and running, I (`theoretical`) have transcribed some key algorithms from C++ to Python.  For example, how many resources\nare consumed by a vote transaction?  The `rcdemo` script allows us to find out:\n\n```\n\u003e\u003e\u003e from rcdemo import *\n\u003e\u003e\u003e count = count_resources(vote_tx, vote_tx_size)\n\u003e\u003e\u003e count[\"resource_state_bytes\"]\n499232\n\u003e\u003e\u003e print(json.dumps(count))\n{\"resource_count\": {\"resource_history_bytes\": 133, \"resource_new_accounts\": 0, \"resource_market_bytes\": 0, \"resource_state_bytes\": 499232, \"resource_execution_time\": 0}}\n```\n\nThe `count_resources()` function is *stateless*.  That means all of the information needed to do the calculation is contained in the transaction itself.  It doesn't\ndepend on what's happening on the blockchain, or what other users are doing.  [1] [2] [3]\n\n[1] Although it is possible that the calculation will change in future versions of `steemd`, for example to correct the [bug](https://github.com/steemit/steem/issues/2972) where execution time is always reported as zero.\n\n[2] For convenience, some of the constants used in the calculation are exposed by the `size_info` member of `rc_api.get_resource_params()`.  Only a `steemd` version upgrade can change any values returned by `rc_api.get_resource_params()`, so it is probably okay to query that API once, on startup or when first needed, and then cache the result forever.  Or even embed the result of `rc_api.get_resource_params()` in the source code of your library or application.\n\n[3] `rcdemo.py` requires you to also input the transaction size into `count_resources()`.  This is because `rcdemo.py` was created to be a standalone script, without a dependence on any particular client library.  If you are integrating `rcdemo.py` into a client library, you might consider using your library's serializer to calculate the transaction size automatically, so the caller of `count_resources()` doesn't have to specify it.\n\n### Resources\n\nLet's go into details on the different kinds of resources which are limited by the RC system.\n\n- `resource_history_bytes` : Number of bytes consumed by the transaction.\n- `resource_new_accounts` : Number of accounts created by the transaction.\n- `resource_market_bytes` : Number of bytes consumed by the transaction if it contains market operations.\n- `resource_state_bytes` : Number of bytes of chain state needed to support the transaction.\n- `resource_execution_time` : An estimate of how long the transaction will take to execute.  Zero for now due to [Steem issue 2972](https://github.com/steemit/steem/issues/2972).\n\nThe resources have different scales.  The resources use fixed-point arithmetic where one \"tick\" of the resource value is a \"fractional\" value of the resource.  Right now, the resource scales are scattered in different places.  The `count_resources()` result has the following scale:\n\n- `resource_history_bytes` :  One byte is equal to `1`.\n- `resource_new_accounts` :   One account is equal to `1`.\n- `resource_market_bytes` :   One byte is equal to `1`.\n- `resource_state_bytes` :    One byte which must be stored forever is equal to the `steemd` compile-time constant `STATE_BYTES_SCALE`, which is `10000`.  Bytes which must be stored for a bounded amount of time are worth less than `10000`, depending on how long they need to be stored.  The specific constants used in various cases are specified in the `resource_params[\"size_info\"][\"resource_state_bytes\"]` fields.\n- `resource_execution_time` : One nanosecond of CPU time is equal to `1`.  The values are based on benchmark measurements made on a machine similar to `steemit.com` servers.  Some rounding was performed, and a few operations' timings were adjusted to account for additional processing of the virtual operations they cause.\n\n### Resource pool levels\n\nEach resource has a global *pool* which is the number of resources remaining.  The pool code supports fractional resources, the denominator is represented by the `resource_unit` parameter.  So for example, since `resource_params[\"resource_params\"][\"resource_market_bytes\"][\"resource_dynamics_params\"][\"resource_unit\"]` is `10`, a pool level of `15,000,000,000` actually represents `1,500,000,000` bytes.\n\n### Resource credits\n\nThe RC cost of each resource depends on the following information:\n\n- How many resources are in the corresponding resource pool\n- The global RC regeneration rate, which may be calculated as `total_vesting_shares / (STEEM_RC_REGEN_TIME / STEEM_BLOCK_INTERVAL)`\n- The price curve parameters in the corresponding `price_curve_params` object\n\nFor convenience, `rcdemo.py` contains an `RCModel` class with all of this information in its fields.\n\n```\n\u003e\u003e\u003e print(json.dumps(model.get_transaction_rc_cost( vote_tx, vote_tx_size )))\n{\"usage\": {\"resource_count\": {\"resource_history_bytes\": 133, \"resource_new_accounts\": 0, \"resource_market_bytes\": 0, \"resource_state_bytes\": 499232, \"resource_execution_time\": 0}}, \"cost\": {\"resource_history_bytes\": 42136181, \"resource_new_accounts\": 0, \"resource_market_bytes\": 0, \"resource_state_bytes\": 238436287, \"resource_execution_time\": 0}}\n\u003e\u003e\u003e sum(model.get_transaction_rc_cost( vote_tx, vote_tx_size )[\"cost\"].values())\n280572468\n```\n\nThe `model` object created in `rcdemo.py` is an instance of `RCModel` which uses hardcoded values for its pool levels and global RC regeneration rate.  These values were taken from the live network and hardcoded in the `rcdemo.py` source code in late September 2018.  So the RC cost calculation provided out-of-the-box by `rcdemo.py` are approximately correct as of late September 2018, but will become inaccurate as the \"live\" values drift away from the hardcoded values.  When integrating the `rcdemo.py` code into an application, client library, or another situation where RPC access is feasible, you should understand how your code will query a `steemd` RPC endpoint for current values.  (Some libraries will probably choose to do this RPC automagically, other libraries may want to leave this plumbing to user code.)\n\n### Transaction limits\n\nSuppose an account has 15 Steem Power.  How much can it vote?\n\n```\n\u003e\u003e\u003e vote_cost = sum(model.get_transaction_rc_cost( vote_tx, vote_tx_size )[\"cost\"].values())\n\u003e\u003e\u003e vote_cost\n280572468\n\u003e\u003e\u003e vote_cost * total_vesting_fund_steem / total_vesting_shares\n138.88697555075086\n```\n\nThis is the amount of Steem Power (in satoshis) that would be needed by an account to transact once per 5 days (`STEEM_RC_REGEN_TIME`).\nOur 15 SP account has 15000 SP, so it would be able to do `15000 / 138`, or about `108`, such transactions per 5 days.\n\nYou can regard the number `138` (or `0.138`) as the \"cost\" of a \"standardized\" vote transaction.  It plays an analogous role to a\ntransaction fee in Bitcoin, but it is not exactly a fee.  Because the word \"fee\" implies giving up a permanent token with a limited,\ncontrolled emission rate.  It is the amount of SP which will allow a user an additional vote transaction every 5 days (but it might\nbe slightly more or less, if your vote transactions use a slightly different amount of resources.)\n\n### Integrating the demo script\n\nThe `rcdemo.py` script is a standalone Python script with no dependencies, no network access, and no transaction serializer.  It is a port\nof the algorithms, and a few example transactions for demo purposes.\n\nEventually, client library maintainers should integrate `rcdemo.py` or equivalent functionality into each Steem client library.  Such integration\ndepends on the idioms and conventions of each particular client library, for example:\n\n- A client library with a minimalist, \"explicit is better than implicit\" philosophy may simply rename `rcdemo`,\ndelete the example code, add a tiny bit of glue code, and give it to clients largely as-is.\n- A client library with an automagic, \"invisible RPC\" philosophy might provide a transaction may make substantial modifications to `rcdemo`\nor expose an interface like `get_rc_cost(tx)` which would conveniently return the RC cost of a transaction.  Since the RC cost depends on\nchain state, this `get_rc_cost()` function would call `steemd` RPC's (or use cached values) to get additional inputs needed by stateless\nalgorithms, such as resource pools, `total_vesting_shares`, etc.\n- A client library which has a general policy of hard-coding constants from the `steemd` C++ source code might distribute\n`rc_api.get_resource_parameters()` as part of its source code, as `rc_api.get_resource_parameters()` results can only change in a new\nversion of `steemd`.  (Perhaps this kind of thing is somehow automated in the library's build scripts.)\n- A client library whose maintainers don't want to be obligated to make new releases when values in `steemd` change as part of a new release,\nmight instead choose to call `rc_api.get_resource_parameters()`.  Adding extra performance and security overhead in exchange for the\nconvenience of asking `steemd` to report these values.\n- A client library with its own `Transaction` class might choose to implement class methods instead of standalone functions.\n- A client library in JavaScript, Ruby or Go might transcribe the algorithms in `rcdemo.py` into a different language.\n\nAs you can see, integrating support for the RC system into a Steem client library involves a number of architectural and\ntechnical decisions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteemit%2Frcdemo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteemit%2Frcdemo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteemit%2Frcdemo/lists"}