hyperledger-archives / fabric

THIS IS A READ-ONLY historic repository. Current development is at https://gerrit.hyperledger.org/r/#/admin/projects/fabric . pull requests not accepted
https://gerrit.hyperledger.org/
Apache License 2.0
1.17k stars 1.01k forks source link

Chaincode should be addressed by a function of its code + initial parameters signature #373

Closed ghaskins closed 8 years ago

ghaskins commented 8 years ago

Ignoring multi-signatory/escrow-contract scenarios, basic asset-move transactions in a blockchain could be described as a uni-lateral "send" function which may only be initiated by the sender (validated by digital signatures from key-pairs associated with the account). Therefore, it is important to have confidence in the destination address' legitimacy as the intended target, as the asset-move will generally be irrevocable once the transaction confirms. Short of a compensating transaction at the behest of, and initiated by the destination chaincode, there is no function to revoke a mistake. Specificity with the location/function of the destination is therefore important to gain both confidence in the network (an initiator may verify that an address resolves as they expect) as well as to catch mistakes/discrepancies (validators would only know how to route messages to the "right" code). Fortunately, this should be fairly easy to capture by creating chaincode addresses as a hash of the actual code and initial parameters: address = f(code, initparams) -> hash([code, initparams]).

ghaskins commented 8 years ago

Today chaincode is addressed by the tuple {url, version}. This tuple is fine for identifying the code to instantiate initially but should be translated into a locally cached code+hash(code) as part of deployment

binhn commented 8 years ago

related #202 @prjayach @muralisrini

muralisrini commented 8 years ago

I've tried to summarize an implementation for this issue and #202 in the attached file. The implementation is in https://github.com/muralisrini/obc-peer/tree/chaincode_as_hash_of_code/issue/%23202

issues_202_303.docx

@ghaskins , @prjayach , @jeffgarratt , @angrbrd , @srderson , @binhn - comments please

srderson commented 8 years ago

Thanks for the summary. A few quick questions after reading though it once.

  1. It states "CLI has a new 'name' parameter for invoke/query" but then later states "Invoke/query needs to provide the hashcode". Does it need both? Why would just the hashcode not be sufficient?
  2. It states the deploy ID doubles as the transaction ID. Does the transaction still have an additional unique ID?

In the last part of your doc, you suggest dropping versioning. @ghaskins and I had this discussion on slack and our conclusion was that address = hash({hash(code), contructor, nonce). If version is not a first class citizen, why should we keep name? Couldn't these both be in the "dns" contract?

muralisrini commented 8 years ago

Thanks @srderson

  1. the name is the hashcode. ie, there is just one thing and not two. The hashcode returned from deploy will be the name used for invoke/query
  2. the hashcode needs to be unique. In particular, if the hashcode generated from the tuple matches a previously generated hashcode retrieved from ledger, we need to return an error

I think the doc needs to clarify "name" better. As mentioned in (1) it is just the hashcode. In dev mode the user really supplies a "name" in lieu of a generated hashcode.

prjayach commented 8 years ago

Looks great, @muralisrini. Couple of questions/comments:

  1. You mention that deploy no longer builds the docker image. Is there a check before every chaincode invocation as to whether a build is necessary? Is this already done in your implementation?
  2. I vote for retaining version. Invariably, smart contracts will evolve over time and users will want to deploy newer versions of the contract, while still maintaining record of the older versions. Eventually, we should build in the ability to prevent invocations of old versions when newer versions have been deployed - this will be a very useful feature, in my opinion. I am in talks with a client for a trade finance application and they really like the versioning feature - specifically, they are interested in modifying a contract over time, maintaining a link to transactions that happened even in older versions (not having to call it an altogether new contract with no link to the past), prevent older versions from being used once newer versions have been deployed.
muralisrini commented 8 years ago

Thanks, @prjayach

  1. To be clear, there were two builds getting done for a deploy request. (1) in devops before a transaction is submitted to the system and (2) in chaincode when the transaction was executed. I just got rid of 1 as unused and unnecessary (ie, its just a low level detail I wanted to call out). We just need to compute the targz and the hashcode for 2 to work. 2 is untouched. Having said that, code currently does not recreate docker image if it got wiped out for some reason. But now that the groundwork is in by way of generating hashcode from files, such a check will fit neatly in the framework - basically untar the bytes from the transaction (if it exists) and compute the hashcode again (should be idempotent as the transaction is immutable but good to check). 2 (Pro) - Semantically version is identical to nonce in @ghaskins and @srderson scheme, isn't it ? Everything else in the tuple remaining same, version would compute a different hashcode. I'm fine with retaining it as long as we don't leverage underlying container support for supporting it at that low level. Docker supports that today but the new implementation does not leverage it. And a different container technology might not support versioining or might treat it differently. By making the version just another byte array that goes into the hashcode computation we keep implementation independent of container technology. From user level as they always deal with the hashcode for invoke/query, it doesn't matter how the image is generated. 2 (Con) - Version has the feel of higher level construct. Remote path's naturally have versioning schemes embedded in them. In the same vein, local paths too can have version in them imposed by a higher level versioning construct. To me it feels right that paths have version component in them making an extra version field superfluous.
muralisrini commented 8 years ago

Updated doc based on above comments : issues_202_303.docx

Interesting ... the attachment link above is an example of the embedded versioning (or nonce) found in remote paths mentioned in "2 (Con)" above :-) . Same filename but different path.

prjayach commented 8 years ago

@muralisrini

  1. Going back to the deploy transaction and recreating the image if needed is what I was asking about. I understand now that it needs to be added once this piece is in. All good.
  2. Yes, not asking for supporting it at container level. Only one version of a chaincode will run in a container at any point of time. The versioning will help queries and analytics later (I can query for all transactions across versions, for instance). Leaving it implicit in the path means that the system does not know that one deployment is the next version of a previous deployment - then there is no way to prevent invocations of the older versions or querying for transactions across versions. You are leaving all that for higher layers to manage, which can be painful.
srderson commented 8 years ago

@muralisrini

The doc states "detect identical deployments and flag error". What is "identical" here? The chaincode ID or the transaction? It should be impossible to have identical transactions as it contains a nonce. It should be possible to deploy multiple instances of a chaincode with the same code and init params.

Does deploy return hash(code) or hash(transaction) or both?

The doc mentions MD5. Why use MD5 over SHA which we're using elsewhere? There's an existing ComputeCryptoHash function in utils.go.

binhn commented 8 years ago

If I read correctly, the hash is computed by hash(bytes of files, path, version, init function name, init param values).

Our primary goal (1) is to satisfy #202; that is, when we exec the deploy TX, we can make sure that we are using the same code that's being sent without any modification -- kind of checksum. Our secondary goal (2) is to be able to tell if a chaincode has been deployed and reject the duplicates. Yet the third goal (3) is not to disable any future extension notion of a chaincode instance; that is, a chaincode may be instantiated multiple times with different representations (like, new Rectangle(3,2)) without redeploying.

I think @muralisrini 's solution meets all these goals. The question in my mind is whether there're any extra things in the hash computation that we don't need. Either version or path seems extra to me. Either one would satisfy @prjayach 's comments.

I agreed with @srderson that we should use utils.ComputeCryptoHash so that we can isolate any potential future changes to the hash function that we use in the system.

muralisrini commented 8 years ago

@srderson : @binhn 's reading of the implementation is correct. Original goals of unique transaction ID for EVERY transaction has been modified to "unique transaction id for every unique deployment and for all invoke/query" transactions. This is what makes a deployed transaction id to also be a unique name. Note that if the deployed transaction id is not unique, we'll have to keep a map of (transactionid, hashcode). The modified semantics eliminates need to maintain that map.

On using one of Path or Version to compute hash : well, if we allow user to specify both, we'll have to include both to compute hashcode. Say user specifies 2 deploy's differing only in version. If we leave version out of the hash, we have to (1) use docker's version to differentiate and (2) have user provide version in addition to name for every invoke/query. Either we allow user to specify (path,version) or just (path) but in either case all specified elements will have to be in hash.... unless I'm missing something ?

On using SHA : we can use any algorithm that makes sense (indeed, there's a commented out SHA3 line in hashfromcode.go to hint that possibility). I used MD5 in the end as we get back smaller strings. There may also be some performance benefits with MD5.... So unless there's advantage of collision avoidance or something, perhaps we could standardize on both (say with a utils.ComputeMD5Hash) ? I'm mainly thinking smaller strings will avoid future limitations with different container technologies.

srderson commented 8 years ago

MD5 has known collisions, SHA-2 and SHA-3 do not. I suggest not using MD5. I don't understand "smaller strings will avoid future limitations with different container technologies."

muralisrini commented 8 years ago

@srderson : agreed. I just meant there may be name length restrictions if we move from docker to something else in future. but that's not strong enough to contend against collision / uniqueness arguments. I'll play with utils.ComputeCryptoHash and push the change if it works out.

srderson commented 8 years ago

@binhn do we have an existing issue open for "Yet the third goal (3) is not to disable any future extension notion of a chaincode instance" or should we open a new one?

If someone wants to create multiple instances today, is our suggestion to essentially put some type of instance ID in the chaincode constructor?

The original idea behind versioning was that you could say something like "invoke this chainchode and invoke the latest version, up to version 3.0". Now if the client is passing the transaction ID to invoke a chaincode and the transaction ID contains the hash of the code, it's too specific as different versions would presumably have different code.

One partial way to resolve this ... versions could be mini blockchains. For example, when I deployed version 3 and would like a previous deploy transaction to be version 2, the transaction ID would be hash(bytes, path, init params, version, AND, hash of version 2 transaction ID). Version two could then reference a version 1. This way the client could securely reference version 3 and securely know that versions 2 and 1 are previous versions.

The problem remains for how to do things like reference version 1 and execute a future version or disable version 1 because there is a version 3. I think these require the OBC server to treat versions as a first class citizen or write system chaincodes that you call through to perform these functions.

kletkeman commented 8 years ago

@srderson I raised a similar set of issues back some weeks. Versioning is usually required as a way to denote contract / API compatibility levels so that the user of a contract does not have to explicitly manage that. It also works very naturally with version control systems, which will presumably be used by the developers of said contracts. I'm not entirely comfortable with the use of version as somehow equivalent to a nonce in this discussion.

The mini blockchain idea is pretty interesting with the caveat that you would only think that way across incompatible versions. I.e. minor upversions stays in the same mini blockchain.

When I went to test multiple assets created by the same chaincode instance a few weeks back, I was rudely awakened to the idea that a chaincode instance must exist for every asset. Which sort of creates a blockchain per asset. I cannot quite grasp how a fairly high overhead design works in a contract based world, where everything in the IoT landscape could become an asset managed by a smart contract. So a design that allowed a new asset to be created without the complete build / deploy cycle would be very welcome I think.

Apologies if I have misinterpreted this discussion somehow.

kletkeman commented 8 years ago

@muralisrini Just curious how a container technology that had length restrictions incompatible with SHA could flourish in today's world?

muralisrini commented 8 years ago

@kletkeman hashcode ends up in the name of the image/container. One can imagine limits on image/container names. Also these names have to be used from CLI, browsers, apps, etc. As long as we don't end up with ridiculously long names, its fine. In any case the hashcode function is on the periphery of the implementation and quite independent and easy to change.

muralisrini commented 8 years ago

pushed change to use SHA3 in hashcodefromcode.go. Also cleaned up test cases to use Paths. All tests ran successfully.

https://github.com/muralisrini/obc-peer/tree/chaincode_as_hash_of_code/issue/%23202.

muralisrini commented 8 years ago

After discussions, hashcode == transaction id == chaincode-reference satisfies all needs without requiring a special version field.

To summarize

Given hashcode is the transaction id, existing "ledger.GetTransactionByUUID" will retrieve the deploy transaction for the chaincode and can be used to build other queries.

@prjayach pointed out that we could go one step further to maintain an index for saying hashes x1, x2, x3 are from the same path. This would provide the "relationship" between the chaincodes.

@binhn, @frankyclu : re your desire to generalize "relationship" between chaincodes... there seems to be an opportunity here. What @prjayach is suggesting is a "same-path" relationship. Are relationships useful concepts to bubble all that way up so users can create relationships and bind chaincodes to them ?

kletkeman commented 8 years ago

@muralisrini : There was some discussion before Christmas suggesting that it would be useful to be able to deploy a chaincode and then call init repeatedly to create assets in the chain that would be managed in a sort of sub-chain way. For example, a shipment of cars with events recorded against each VIN as a separate asset. Using the method you describe, it seem that this will that require that every tracked car have its own instance of chaincode with a full build / deploy / init. Is my interpretation correct? Thanks.

muralisrini commented 8 years ago

@kletkeman : calling init repeatedly would create new chaincode instances, correct. However that same functionality can be achieved by a single application tracking all cars, couldn't it ? From discussions, there are two models in general (1) 1 chaincode per resource (init with resource and deploy) and (2) chaincode managing resources via state (resource lifecycle managed via invoke).

Is there something in the approach you describe not covered by the above two ?

kletkeman commented 8 years ago

@muralisrini There was a discussion about this a month or so ago. The chaincode deploy per resource is rather network and compute intensive and would thus limit us to slow cadence applications.

The single chaincode managing resources in a map (let's say) is better on system resources and could be the best way to go. There is the issue that the full state of the map may have to be hashed on each write, which does not scale very nicely. Has that been discounted as unnecessary? Or are the performance implications considered acceptable?

The compromise position would be to separate deploy from resource / asset creation and management. Of course, this would require that the blockchain be directly queried by resource ID rather than an internal map, which may have similar performance.

The map solution looks good if an Achilles' heel is not foreseen.

ghaskins commented 8 years ago

I think it is important to separate the functions of making code available for instantiation, and the actual instantiation of the chaincode to an instance. While I have seen some mention of a delineation between Deploy and init(), both of these steps will have some similarities w.r.t hashIds requirements, however. Therefore I think this is relevant to the to the OP subject.

Background

Rather than a single "Deploy" operation, I would argue that it should be something like a "Publish" + a "Create" operation, where the Create references a specific codebase from a previous Publish, and results in an instanceID that can serve as the target for further operations (such as Invoke).

This is partly because we need to recognize that in many use cases, the author of the chaincode will be a different entity from the parties that instantiate and/or invoke it. It's also to allow the consensus layer to achieve agreement that all validators see the same code at the other end of the URL passed in before anyone agrees to consume it.

Publish

The basic notion with the Publish operation is to allow an entity or entities to publish chaincode in a coherent way across the network and to allow consumers of the chaincode (the instantiators and/or invokers) to have trust that they are instantiating the code they think they are. The closest analogy I can think of is pushing an AMI to AWS as a discrete step from creating an instance from an AMI. This operation makes it available "in the catalog" and can be displayed as such to a UI, etc.

Namespaces

Another component of this is the namespace associated with this push. I envision a "github" like concept where anyone can create an account ("ghaskins"), and within that account, any number of repositories may be created. Within a repository, any number of versions may be pushed. The namespace would be hierarchical in nature, like a filesystem or REST/URI, e.g. username/repository/version, e.g. "ghaskins/gregs-swap-contract/v1". Only "ghaskins" has authority to manipulate the ghaskins/* namespace, and publising new code to ghaskins/gregs-swap-contract creates a new version. Each new version has a unique id as a function of hash(hash(code), username, repository, version) -> ImageID.

Reputation

Being able to attach trust to a namespace will be important. E.g. if the system enforces that only an entity that possesses credentials for "ACME Corp" may publish repositories/versions under the namespace /acmecorp, then the burden of due dillgence and discovery is reduced for anything under /acmecorp/* vs a random pool of available code.

Versions

I agree with the comments that versions are important. "ghaskins/gregs-swap-contract" may evolve over time. Its important to allow other entities to be able to identify a specific version of a contract (e.g. v3 is the one our legal team vetted), as well as the relationship (e.g. I see there are newer versions of the contract we love so much...should we consider using the later version in future transactions?). To that point, pushing a new version of a contract should not invalidate previous versions per se. Current instances may not want to allow new code without specific considerations. Future instances may wish to continue using versions of the code they have spent time vetting. Therefore, allow the chaincode publisher to decide how to maintain their namespace (e.g. ghaskins/*. Allow operations for creating new repositories, pushing new versions, or retiring old versions, deleting repositories, etc. But don't do anything automatically.

Create

Create operations reference a (presumably previously established) ImageID, and couple it with the constructor parameters and an nonce: e.g. hash(ImageID, parameters, nonce) -> InstanceID.

Summary

"InstanceID" in the above proposal carries the same crypto properties as defined earlier. However, by splitting the operations we neatly provide the ability to re-use chaincode, build trust, provide a reputation system, etc.

kletkeman commented 8 years ago

@ghaskins Well stated. Agree completely.

johncohn commented 8 years ago

@ghaskins Agree with your assessment. I see the ability to create multiple instances of a single contract as key for two reasons. First it makes it easier to guarantee that multiple entities share exactly the same contract specifics. Second I believe it will be much more efficient for size and computation when you have very many instances intended to run the same contract.

muralisrini commented 8 years ago

Thanks @ghaskins @kletkeman @johncohn and others..

Let me attempt to summmarize above comments from an " implementation" point of view.

Currently deploy is a transaction with ( path + code + initialization data ). Every time one of the tuple changes, user has to create a new deploy transaction with the entire tuple.

In particular, this approach lumps code and data together. A common pattern is run the same code with different data (e.g., instantiate the same contract with different initialization data). This is naturally implemented by reusing the code as opposed to deploying the same code each time.

Some implementation notes

From user point of view, if above are the only changes, there isn't a functional difference between 2 deploys vs a deploy and an invoke (there would be performance and scalability benefits - @kletkeman @johncohn comments). However this separation allows us to extend the system (such as "Namespaces" in @ghaskins comment) and control instantiations.

kletkeman commented 8 years ago

@muralisrini Good summary. There is one difference between 2 deploys and one deploy and 2 instantiations that you do not mention: every node in the network must deploy / build and instantiate for every resource / asset with the current scheme, whereas only one deploy / build will ever be necessary for any given version of the chaincode / contract under the proposed scheme. In a high-volume scenario, this could result in a fairly massive performance improvement at the network scale.

prjayach commented 8 years ago

I like the proposal, but seeking clarifications - in today's scheme we can maintain an index of chaincodeID to its path + code + initialization data. With this index, we can realize different versions (if multiple IDs use the same path, init data but different code, we can mark them as versions), different instantiations (multiple IDs using the same path, code but different init data). Once we realize from this index that a new deploy is only an instantiation of an older deploy, we can avoid rebuilding the image (if needed). Even otherwise, docker has a caching mechanism that is quite good at realizing that a new build has the same dockerfile instructions as a previous build, making subsequent builds of the same code very quick. What are the key benefits of splitting deploy and instantiate that aren't realizable with today's bundled deploy?

prjayach commented 8 years ago

One possible advantage of the bundled deploy is that at the time of invoke, I need to refer back to only 1 previous transaction (the deploy) to ensure that the code I am running is actually the one that was initially deployed (for security, Issue #202 which was also covered with @muralisrini's implementation for this issue). In the proposed change, I might have to refer back to 2 transactions at the time of invoke?

ghaskins commented 8 years ago

@prjayach one of the key benefits is ensuring the confirmation consensus on the code in question. The basic notion of chaincodeID = deploy(url, ...) in of itself doesn't ensure that the entire network sees the same thing at the $url. Yes, I can decompose chaincodeID after the fact to see if it meets expectations, but to my knowledge there's nothing that says all other validators will come to the same conclusion per se. And even if chaincodeID is negotiated by consensus, what if it doesn't meet my expectations? Destroy the instance and start again? What if someone else already started interacting with the address in the meantime?

With the two phased approach, there is no ambiguity: Create() takes an ImageID, which by definition can only exist for a very specific peice of chaincode and only if the consensus agrees it was published and available to execute across the entire cluster. This happens before the address is active.

I admit there are ways this could probably be accomodated with a single Deploy, however. For instance, the transactor could pass the hash of the code in (e.g. chaincodeID = deploy(url, hash, ...). However, this seems inelegant to me. Given that there seems to be agreement that the concept of "multiple instantiations of the same code" is a good one, let me flip it around on you. Is there a reason it makes sense to only support a one-shot Deploy? After all, "Deploy" can be modelled as a composition of the Publish+Create verbs, so its not like it needs to go away per se. Why would we not want to make this a first class notion? It seems cleaner to me to simply "re-instantiate the AMI" each time it is needed rather than to keep uploading the AMI every time. I understand there are internal optimizations that would eliminate the actual re-import, but just the need to specify the re-deployment seems more awkward to the user to me.

Regarding the advantage of looking back 1 vs 2 transactions, this sounds like an implementation issue. Generally speaking, I would expect the notion of valid chaincodeIDs and their mappings to be something that could be maintained as derived state within the validator. Either the chaincodeID is known (because it was previously instantiated), or it isnt. At this stage, we do not need to validate the code hash or anything other than checking if the instance exists.

The key take-away in the orignal request is that the goal of hashing the code isnt a mechanism to protect against the corruption/manipulation of things internal to the validator (such as the docker container). Its simply to provide a mechanism to disambiguate "chaincodeID" from its expected function for the benefit of the network consumers.

muralisrini commented 8 years ago

@ghaskins : "The basic notion of chaincodeID = deploy(url, ...) in of itself doesn't ensure that the entire network sees the same thing at the $url. "

The above reads that it is possible that the code might turn out to be different on each validator. If that reading is correct, its not accurate. The peer that fields the request will access the URL and construct the code bytes and distribute that to all validators. That is, all participants in consensus will act on the same code bytes. And once committed to the block, its that codebytes that can be redeployed and not the path.

Another way to think about this is that the "path" - remote or local - is just a convenience. We could have implemented by requiring the developer (end user) to send the code bytes directly.

While we are on this topic, one possible pattern (good practice?) would be for the fielding peer to be an on-premise non-validator to construct the code and distribute to validators.

In any case, the above difference - though important - is minor for this discussion. All the key points still hold.

kletkeman commented 8 years ago

@muralisrini This discussion has been going on for quite some time with versioning and deploy / init separation and other issues being in play. This is the first time I've seen it mentioned that only initial fielding server does a build of the chaincode, with all others getting a copy of the compiled contract bytes. I seem to remember seeing the validators all performing a build on the chaincode ... was this feature added recently?

Also, it seems that the version parameter has been removed from the peer. Does this mean that the contract that is deployed cannot be tagged with the contract version for simple human debugging and auditing purposes? Also, the devnetsetup document has not been updated to exclude the version.

muralisrini commented 8 years ago

@kletkeman : once the transaction has been constructed, each validator uses the bytes directly (instead of using the path) to build the chaincode. I didn't mean to imply the chaincode executable gets deployed to each validator. That behavior is not changed. What was changed with this fix to make the behavior for "remote" paths consistent with local file system paths. That works need to be ironed out a bit but the main pathlines have been streamlined.

There is discussion above on the removal of the version field....and you are right about the old doc. Will need to fix that along with all the doc work that's happening.

ghaskins commented 8 years ago

@muralisrini regarding code byte distribution, that sounds potentially better than distributing the URL but note that there are still other problems identified even if there is consensus on the code.

Can you comment on what constitutes "construct the code bytes"? Is this the simple downloading of the URL and distributing source? Or is it compiling the source to byte-code/native-code and distributing the result? It's important to note that its critical that each validator must operate on the raw source (e.g. each validator must take source as input and generate hashes and bytecodes locally). Otherwise, it is an attack surface where the byte-code/native-code could diverge from the source.

muralisrini commented 8 years ago

@ghaskins : correct, "construct the code bytes" is simple downloading of the URL and distributing source.

kletkeman commented 8 years ago

@muralisrini Um .... I've not seen that usage of codebytes before ... it sounds so much like bytecode that anyone would assume it. I suggest that "source code" be used when communicating the concept. I.e. we load the source code from the path and build it locally. The source code itself is propagated through the network so that each validator can verify against the hash that is sent with it that it is seeing the same contract.

This is definitely better than sending compiled code as @ghaskins mentions, and it will handle network interruptions very well in cases where the path is a remote URI. In that case, losing connectivity to the URI does not affect the ability of the segment on the wrong side of the network outage to carry on propagating and validating.

ghaskins commented 8 years ago

@muralisrini ok, thanks for clarifying. Any other thoughts about the other issues? (e.g. either specifying the hash as part of the Deploy() parameters, or (my preferred route) splitting up the operation into Publish+Commit and creating Deploy() as a composition of the two). The former satisfies my major concerns though I still think it would be substantially more elegant to make the re-use first class with two operations. Also, the former demands that the user understands how to compute or, at least, obtain the hash. The latter makes their awareness optional.

muralisrini commented 8 years ago

@ghaskins : the two verb approach of having another verb to "instantiate" from an previously created (or Published to use your term) chaincode seems to be the right thing to do.

Of course what implementation form this would take is another question. At the extremes are container-per-instance and context-per-instance (ie, abstract the instance into a context to be passed to 1 chaincode). While the former seems like a natural fit, we could quickly run into scalability issues. The later might be more practical.

@binhn - comment please ?

binhn commented 8 years ago

It looks like my 3rd goal above (new Rectangle(3, 2)) has been taking on a new life. The discussion here is all great. Many thanks!

Currently the deploy transaction packages the TX (including security, source code, constructor, params, tx-id) and broadcasts it to all validators. The tx-id is a hash(code, path, constructor, params).The validators then build and launch the chaincode containers as part of the TX execution.

This is a service model (like J2EE servlet if you're old enough). Once deployed, it can accept and process requests. For example, in REST, we do /cars/{car-id} or /customers/{customer-id}/balance to request a service, and in particular, it can address an instance of an object (a car via the car service without instantiating another car service). Same reasoning, a chaincode is a service, so instances of a thing may use parameterization -- different thought process but same result.

I've been pondering if instance of a chaincode is necessary given that middleware developers have been used to the service-oriented model, especially RESTful style. What is it about blockchain that requires more than service-oriented model? I am still not satisfied with the philosophy yet but acknowledge that to certain set of population, it could be more natural in the thought process.

For implementation, I agree with @ghaskins that we should introduce publish and create transactions in addition to the invoke transaction. Keeping deploy around would complicate the model later on.

kletkeman commented 8 years ago

Another question: Say that I create an asset instance with ID XXXXXX and get back chancode instance ID 123456. I must from now on target 123456 with events for XXXXXX, which means I have to maintain a mapping. Is it / will it be possible to look up a chaincode instance via the original XXXXXX for end points that do not have access to the mapping? To put it another way -- can I find the chaincode ID now via asset ID, and will it change when deploy and init are separated?

christo4ferris commented 8 years ago

this is ancient, and just referencing the issue itself, it seems impossible to tell whether it is still a thing.

@ghaskins @binhn @muralisrini @srderson can this be closed (aside from the fact that it contains a very nice discussion!)

ghaskins commented 8 years ago

I think it may be closed. It's not like it deleted... just carries a more meaningful status.