Giter VIP home page Giter VIP logo

pycc's Introduction

PYCC

PYCC is a Python library for implementing Crypto-Conditions for the Komodo blockchain.

It's like a Django Web Framework for CC.

Concepts

In PYCC you declare a schema for a CC contract, and you get a set of functions to create and validate transactions.

PYCC apps can be plugged into the Komodo blockchain by building komodo with blockchain support (link TODO).

Schema

The Schema is where you declare the structure of your CC app. A schema contains CC apps, which define transactions.

See an example of a faucet app defined as a PYCC schema.

Consume and Produce

The Schema then gives you two functions: consume to turn a tx into params (while also validating the structure), and produce to to create a tx from params.

During the on-chain validation, the transaction is consumed in order to validate it's structure, and the business logic is performed on the resulting params rather than the TX itself.

                             Consume (also validates)

                           +-------------------------->


      +--------------------+                          +--------------------+
      |                    |                          |                    |
      |    Tx Binary       |                          |     Tx Params      |
      |                    |                          |                    |
      +--------------------+                          +--------------------+

                           <--------------------------+

                               Produce Tx from Params

Tx deconstruction

PYCC conceptualizes transactions as function calls, that have many parameters and a tuple of outputs.

The number of inputs and outputs may vary, but the structure is static. When a variable number of inputs is required, that is encoded as a list of inputs, so the structure does not change.

txs

Setup

Install rust: https://www.rust-lang.org/tools/install

make pycctx
virtualenv -p python3 .env
.env/bin/activate
pip install -r requirements_test.txt

To run tests:

pytest

pycc's People

Contributors

alrighttt avatar ssadler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pycc's Issues

pycctx: bad scriptPubKey encoding for some condition structures

Alrighttt@88e7c4d

There is a test here in my fork which (I believe) demonstrates that pycctx is producing bad signatures for conditions with the following structure:
{'type': 'threshold-sha-256', 'threshold': 3, 'subconditions': [{'type': 'threshold-sha-256', 'threshold': 1, 'subconditions': [{'type': 'secp256k1-sha-256', 'pubkey': '03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12', 'signature': 'b768f3ea235aae45ccad0d7b6907a6c45b22ab9b16eeee7db38bb2a181d576317aa18fa8664eaf5d16c7a676b189bbd6ecce9291fcd48e77940574beb6b8ee20'}]}, {'type': 'eval-sha-256', 'code': 'e4'}, {'type': 'eval-sha-256', 'code': 'e5'}]}

It however does not have any issue with the "typical" structure:
{'type': 'threshold-sha-256', 'threshold': 2, 'subconditions': [{'type': 'threshold-sha-256', 'threshold': 1, 'subconditions': [{'type': 'secp256k1-sha-256', 'pubkey': '03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12', 'signature': '3956faf39b6c3d051e03f883dc9067ede9fce0d29f13d3a9b8b59775ca874e8357a66829ad7c41712303c48e3a5dda40d5e25e641f45436e51a7ff2616fdc6de'}]}, {'type': 'eval-sha-256', 'code': 'e4'}]}

Module Refactor

The goal is to remove the pycc.py monolith:

  • All script classes go in script.py
  • CCApp goes in app.py
  • All encoding functions go in encoding.py

pycctx needs to distinguish between p2pk and p2pkh while signing

As of right now, it seems the pycctx app is assuming all normal(non-CC) inputs are p2pkh. It's possible I am overlooking something here, so if this is not the case, please let me know. It would be preferable if pycctx could automatically detect whether it is p2pk or p2pkh.

Figure out what needs to go in standard contract library

PYCC should have a module pycc.standard, which includes a schema with contracts that you can take "off the shelf" for use in your blockchain.

  • Tokens is fundamental, it's expected that every application would want to make heavy use of tokens.
  • Faucet is a pretty basic one that could be useful in quite a few cases, and is very useful as a "hello world" example of how CC contracts work due to it's simplicity.

What else should or could be provided?

make OP_RETURN data format safe and efficient

['faucet.drip', ([1], [1, 1]), {}, '03a8339e98111ee9dc74a956164e6507a67005f4a2c45c0481f1b9d7c3c7d5fd9a', '03a8339e98111ee9dc74a956164e6507a67005f4a2c45c0481f1b9d7c3c7d5fd9a']"

If a pubkey is stored like this in OP_RETURN by pycctx, it it first being converted to ascii prior to being added to the OP_RETURN. This results in the data taking twice as much space.

Introducing user-defined parameters into schema validation

While creating the faucet PoC, I have realized that there is no clear way to add any degree of variation to the validation schema. Many existing CCs use the concept of "plans" to set user-defined variables that will affect future validation. These parameters are typically set in a "plan creation" transaction's OP_RETURN.

https://github.com/Alrighttt/pycc-1/blob/f424474ae1f0b885f90c38aaf48416964d59492a/pycc/examples/faucet.py#L96
As an example, we need some way of setting DRIP_AMOUNT here based on the original create transaction.

pycctx: mixed mode

I believe we need CC mixed mode implemented into pycctx for it's spam prevention features.

I have merged mihailo's cc_mixed_dev branch into my pycc branch, and komodod is able to redirect the validation to pycc cc_eval as expected. However, pycctx, as far as I can tell, gives no way to produce/sign CC mixed mode conditions.

I am opening this issue as a place to discuss whether we will implement CC mixed mode. If so, to discuss who can work towards implementing it. If not, to discuss viable alternatives for spam prevention.

Rust CC quality

For now the rust code should work, but before it's put in production it needs a little more attention:

  • examine / remove all use of expect and unwrap
  • examine / remove all use of unsafe vector indexing ie vec[i]
  • refactor modules into something sensible

How to connect inputs to outputs / validation strategy

In regular CC, each application has an eval code which is 1 byte that is stored in the SPK to indicate that a certain validation needs to take place. This eval code routes to code which does the validation, maybe just on that input, but more likely for the whole transaction. There may be multiple eval codes in a transaction, so in some cases some eval codes might have knowledge of other eval codes protocols, for example, so they can work with Tokens as well as regular coin.

There is also the FuncID, which is an additional instruction marker inside the transaction. The transaction might have multiple FuncIDs for different eval codes, and the FuncID specifies a routine that should be validated, for example, Faucet create / Faucet transfer.

In PYCC, the situation is very similar but with some differences. Currently at least, there is only one "eval code", and everything with this eval code is routed to PYCC. Then, the transaction has a FuncID, like "faucet.create", which PYCC uses to find a model inside a schema. The model specifies everything about the transaction, and it is fully validated. The schema could look like:

schema_link = SpendBy("faucet.drip", pubkey=global_addr['pubkey'])   
                                                                    
schema = {                                                           
    "faucet": {                                                      
        "create": {                                                  
            "inputs": [                                              
                Input(P2PKH())                                       
            ],                                                       
            "outputs": [                                             
                Output(schema_link)                                  
            ],                                                       
        },                                                           
        "drip": {                                                    
            "inputs": [                                              
                Input(schema_link)                                   
            ],                                                       
            "outputs": [                                             
                Output(schema_link, RelativeAmount(0) - 1000),       
                Output(P2PKH())                                      
            ]                                                        
        },                                                           
    }                                                                
}                                                                    

In the above schema, the SpendBy class is configured with the global pubkey for the faucet, and encodes a CC condition with the PYCC eval code. It does not need to encode a special eval code because it has a validator that checks that the input is the correct type...

Hmm, wait. The type of the input transaction is not specified anywhere, so it could be spending from any transaction that is using SpendBy("faucet.drip") as an output script (link). is that what we want?

Well, the thing is that the schema is not designed to interoperate with other transactions that are not part of the schema. So what if somebody posts a transaction with a SpendBy("faucet.drip") output that does not pass validation?

Ok, so there needs to be a function to validate that CC input transactions have been validated (is_cc_validated). This can be validated by:

  1. Has a CC input itself, or
  2. Has a CC output with a visible evalcode, so you know it has passed ContextualCheckOutputs.

So the SpendBy("faucet.drip") script checks that only a faucet.drip transaction can spend that output.

We could also have:

  • SpendFrom("some.tx"), which is the reverse of SpendBy, ie, checks that the parent is a certain type of TX.
  • SpendByMany(["some.tx", "other.tx"]) Allow multiple TXs to spend from a type of output
  • SpendByCapability(Exchange() & NFT()) Rather than specifying exact TX relationships, specify categories / capabilities. This is most similar to the way that Eval codes are used today, but it's not neccesary for the SPK to contain specific eval codes. The "Capability" is an object that encodes the relavent logic, but it does not validate the whole transaction (so there is no IsMyInput neccesary).

Still, this is all up in their air right now, and I feel like I might be missing some things so I'd appreciate to get some feedback and exchange some ideas!

@dimxy @Mixa84 @Alrighttt @jl777

Make a generic CLI interface for schemas

In the same file where the schema is declared, there should be:

from pycc.cli import CLI

if __name__ == '__main__':
    CLI(schema).run()

This should present a generic interface for transaction construction. It should be able to construct transactions from params and sign them (using Hoek for now).

feature request: validation error message handling

When broadcasting a pyCC transaction via komodod's sendrawtransaction command, if the validation fails. We receive this error message:

error code: -26
error message:
16: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)

https://github.com/KomodoPlatform/pycc/blob/master/pycc/lib.py#L346
An assertion such at this one will be displayed in stderr, but the user(or wallet or dapp) will have no indication as to why it failed without having access to stdout of komodod.

It would be useful if we were able to relay the exception back to the user by changing this error message.

This function here https://github.com/ssadler/komodo/blob/b926989fa0602093a694b001ad86192fd26a42d0/src/cc/pycc.cpp#L146 is able to print the exception(along with the assert message), so it is likely a good place to start.
ex:AssertionError: TODO: nice error message

Providing entropy

Many applications will require random numbers entropy. Entropy is distinct from a random number provided by deterministic RNG because parties know that it exists but don't know what it is, yet. This issue is to discuss how best to provide it.

quotes from @Alrighttt

  1. Notariser entropy

We can use notarization hashes or momom data as entropy, but this limits many use cases as it can only happen every 3 minutes at the fastest. It happens every ~10 minutes using default iguana configuration. I believe this is a sufficient source of entropy as it's highly unlikely a single person/party can influence it. (actually, everyone can influence it. Spam some txes and you can be relatively sure no one is entropy grinding.)

Note: there's actually an ethereum contract which provides random entropy and allows anyone to submit a transaction to add to the entropy

  1. Dealer entropy

@jl777 used a method in Dice CC which can support faster times. The "dealer" would create entropy, hash this entropy and broadcast this hash inside a transaction. The "bettor" would then choose one of the dealer's utxos and bet against it. Dealer would then be forced to reveal entropy within some time frame or the bet would default to a loss. Once entropy is revealed, either party can finalize it. I recall some issues with this concept, but I can't remember exactly what they were. If you're interested, can try to dig through on chat logs from the discord server.

  1. Preimage entropy

Another idea: 2 parties, Alice and Bob, both provide a hash where the preimage contains a random seed. After the hashes are confirmed on chain, alice and bob both reveal the preimages, and the random entropy is the hash of both of their preimages. So far, no collisions have been found in sha256, but to make it a little harder there could be a common prefix requirement. This seems very simple so maybe there's some issue with it? It's basically the same as dealer but both parties provide their hash in a single transaction together.

  1. NIST provided

@Alrighttt also mentioned:

https://beacon.nist.gov/home
@dimxy has done some work on pushing data from this api on chain via the "decentralized trustless oracles" concept. I believe this could could allow a dapp to get a new source of entropy per block time.

This seems like it could be useful for some applications, since the NIST interface appears to provide an indexable and signed sequence of random numbers, so that parties could agree on the random number of some future index and then the verification of that random number can be checked on-chain without additional I/O by using the NIST provided pubkey.

There is also https://www.cloudflare.com/leagueofentropy/ and maybe other projects.

A good result would probably be to provide several options with pros and cons of each, and provide an interface to them in a module like pycc.entropy or similar.

standard "global addresses"

We need to decide on a standard model for how pyCC will handle global(private key is publicly known) addresses.

I have made a PoC for how we might do this at:
https://github.com/Alrighttt/pycc-1/blob/b20bd5eae2f307ea07697655708ce1eba8bd2b85/pycc/examples/faucet.py#L76

This method gives each eval code an arbitrary amount of unique global addresses, each user-defined.

As an example of how this works, a user creating a faucet plan would provide an arbitrary string. This arbitrary string is then hashed and the hash is used as the raw ecdsa privkey for the global keypair. This gives us 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140 unique global addresses per eval code. In the very rare case of the string's hash being greater than FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140, we can detect this and simply hash the hash.

From a user perspective(this will not be unique to a faucet CC)....
faucet creator creates a new faucet -
komodo-cli -ac_name=PYCC pycli create <fund amount> <faucetget amount> "my arbitrary string"

creator will then externally advertise that they have created a faucet at "my arbitrary string".

A user will then input this string while using the faucet -
komodo-cli -ac_name=PYCC pycli drip "my arbitrary string"

This is simply a proposal. I am open to suggestions otherwise.

Make faucet work (start here)

  • Test that the transaction that follows a create must be a drip or it will fail (have to make a mock chain object to get the tx lookup function)
  • Make the InputAmount class that is able to generically validate an output amount relative to input amounts
  • Document all business logic rules in examples/faucet.py. Implement the rules that cannot be implemented delcaratively in the function validate_drip.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.