Closed JoshOrndorff closed 6 years ago
It looks like your list above can be broken down into a few classes.
Rename to rchain.js I like that Idea
Wrap the rest of the gRPC API such as show blocks, etc I like that Idea too, but don't think we need to block the npm module for that.
Rename and restructure the existing functions.
I don't think I like that idea. It helps js programmers communicate with the rest of the RChain devs if we stick to common names like listenForDataAtName
instead of readDataByName
. How to the commit_block
and send_block_to_peers
parameters work?
Add crypto (hashing, signing, key management) I don't like that idea. There are already good modules like tweetNaCl, or if you want a nice UX, RSign. I wouldn't say nay if you go ahead and wrap those here anyway, but I'd say it's lower priority than wrapping the rest of the gRPC interface and shouldn't block an npm module.
Just my thoughts.
From @crypto-coder on October 3, 2018 15:58
The gRPC interface provides the functions 'createBlock' and 'addBlock', which are almost always going to be called by the dApp developer after they execute a smart contract, so I provide a way to have them called internally to the function call, as parameters in the function calls: 'commit_block' and 'send_block_to_peers' respectively.
listenForDataAtName
) and then other convenience helpers are also fine keeping name similarity to the extent practicable. So for example, maybe the convenience parameter is called create_block
rather than commit_block
. I like the idea of having those so the js dev doesn't have to call create block manually every time.I don't like the name executeContract
because not all deploys do that. You could be deploying a send or receive that just sits in the tuplespace waiting for its counterpart to come along and cause actual execution.
From @dckc on October 3, 2018 21:51
@JoshOrndorff writes:
It looks like your list above can be broken down into a few classes.
I think the package name deserves its own issue: #22
Hashing out the rest of the API design here is fine with me, for the most part...
Let's stick to ocap discipline, please; that is: this call...
var myNode = RNode(hostname, port);
needs another argument for access to the network:
var myNode = RNode(grpc, hostname, port);
IOU a section for CONTRIBUTING.md.
Also, combining { hostname, port }
seems to be the node.js norm:
http.get({
hostname: 'localhost',
port: 80,
...
-- https://nodejs.org/api/http.html
We could put grpc
in the same object like they do with http agent. (But having a default would cross the ocap discipline boundary, and I really want to hold fast to that.)
From @dckc on October 3, 2018 22:0
Why involve myNode
in hashing?
Hash Data (SHA256): myNode.hashData( data_list, 'sha256');
It's computable locally, without communicating with the node.
Also, why pass the hash algorithm in as a name? Why not just separate functions? Are there any uses for hashing without caring what the algorithm is?
So how about just: sha256( data_list)
. At which point: is there any particular value in re-exporting what's already provided from tweetnacl? I guess nacl.hash
only does SHA-512. Why do we want sha256? why keccak256? why blake2b256?
From @dckc on October 3, 2018 22:2
What is myNode.loadKeyStore( keystore_path )
supposed to do? Does rnode have a gRPC API for getting at its keystore that I missed?
From @dckc on October 3, 2018 22:8
I'm starting to lean toward separate issues for hashing and key storage.
Create new KeyPair: myNode.createKeyPair( alias, add_to_keystore=true ); Get Public Key by Alias: myNode.getPublicKey( alias ); Sign a transaction: myNode.signTransaction( alias, DeployData );
Is there some reason to change from the current API?
const seed = randomBytes(32);
const pair1 = keyPair(seed);
console.log('public key:', pair1.publicKey());
console.log('signature:', pair1.signTextHex('hello world'));
IOU a section for CONTRIBUTING.md.
grpc
and endpoint
as args just as you suggest. Let's just leave it as is.I'm starting to lean toward separate issues for hashing and key storage.
@crypto-coder If you wan to discuss this stuff more, please do open an issue. You're working on the most advanced use case so far, so let us know your thoughts. OTOH, if you're convinced, we can just let that convo die.
From @crypto-coder on October 4, 2018 5:11
Why involve
myNode
in hashing?
Rholang can perform hashing, but it only hashes byte arrays. In my coin-faucet project, I was creating a 'race' where I would store a coin in an account identified by a salted hash (keccak256). The first user to send a transaction with the correct salt would receive the coin. The data being hashed is the name of the coin concatenated with a salt. Everytime I ran the "keccak256Hash" function inside Rholang, I would get something different than what I computed in node.js, off-chain. The keccak256Hash function in Rholang wants a byte array, so I wrote the byte array to stdout, and found that it is prepending 4 bytes in front of my concatenated text. I still don't know how to correctly compute those initial 4 bytes, but when I figure it out, I feel that we should have a function that other dApp devs can use to compute sha256, keccak256, and blake2b256 off-chain, the way that Rholang internally will compute them. The alternative (addition?) would be to amend the Rholang tutorial to describe how to compute matching hashes off-chain that include the prepended 4 bytes.
Also, why pass the hash algorithm in as a name? Why not just separate functions? So how about just:
sha256( data_list)
We could do a single overloaded function, or different named functions. Ultimately, I think the steps involved in generating a hash will largely be the same for all algorithms. No preference either way.
Why do we want sha256? why keccak256? why blake2b256?
These are the 3 hashing algorithms provided natively inside Rholang.
From @crypto-coder on October 4, 2018 6:0
What is
myNode.loadKeyStore( keystore_path )
supposed to do? Does rnode have a gRPC API for getting at its keystore that I missed?
Not sure how to get access to RNode's keystore, but if that is a thing (by any means necessary), then that is definitely what I would want to do with these functions.
Otherwise, this is a convenience feature that will do many of the same things that RSign provides, but for backend applications. This keystore is a totally contrived file of aliased pub-priv key pairs. Password-protected even. These keys are used for signing transactions. Specifically, a backend system that is acting as an automated oracle would need a way to load keys on demand. Eventually, this keystore idea will need to be a proper RChain wallet / HSM, so these functions will definitely change. For today, this is just a simple, dirty solution.
From @crypto-coder on October 4, 2018 6:23
I'm starting to lean toward separate issues for hashing and key storage.
Created a new issue for key management / signing #26
From @dckc on October 4, 2018 16:9
... it is prepending 4 bytes in front of my concatenated text. ...
I bet that's protobuf encoding. the rholang .toByteArray()
turns any process into its protobuf serialization. We have tests for this; for example, notice how "Bob" turns into 7 bytes worth of hex:
string: rtest({
data: 'Bob',
rholang: '"Bob"',
hex: '2a051a03426f62',
rho: { exprs: [{ g_string: 'Bob', expr_instance: 'g_string' }] },
}),
-- https://github.com/JoshOrndorff/RChain-API/blob/master/test/testRHOCore.js#L14-L19
The inital 4 bytes tell us that this par consists of one exprs
which is a string (and probably its length).
So it's not the hashing function that prepends bytes. It's the business of serializing a process.
So if you want to hash "Bob", i.e. hex 426f62
, then write "426f62".hexToBytes()
and pass that to the hashing contract.
@crypto-coder says:
I feel that we should have a function that other dApp devs can use to compute sha256, keccak256, and blake2b256 off-chain, the way that Rholang internally will compute them.
I've seen a lot of people around the community including myself trip on this encoding thing. I agree the protobuf encoding makes good sense in hindsight, but making it visible is like throwing obstacles in the path to success. Consider this developer story.
I'm a dApp developer who has written a rholang smart contract. I'm now writing the frontend in javacscript. I want to use RChain-API to connect to the blockchain, but I don't want to dig into it's guts or fiddle with bit tweezers. What's my best way to hash the string "Hello World" in such a way that it will verify correctly on chain, and preferably on ethereum or even bitcoin as well?
Ideally the answer is something like call serializeThenKeccak256("Hello World")
.
I agree that it shouldn't be a method on the node instance.
From @dckc on October 5, 2018 2:24
Do ethereum and bitcoins have norms for hashing things beyond byte sequences?
Text encoding can be really tricky: http://intertwingly.net/blog/2008/12/09/Just-use-Unicode
Yeah, I guess I don't know about that. Maybe compatibility with ethereum is a different conversation. But do you agree, @dckc, that the developer I described above shouldn't have to see protobuf to make a hash that will verify on-chain?
A helper function that is not a method on the node seems like the right solution to me. @cryptocoder?
We currently have:
const b2h = bytes => Buffer.from(bytes).toString('hex');
const h2b = hex => Buffer.from(hex, 'hex');
const t2b = text => Buffer.from(text);
though we don't export t2b
.
I guess convenience functions that compose those with function that hash bytes are OK. We already have precedent:
return def({
signBytes,
signBytesHex: bytes => b2h(signBytes(bytes)),
signText: text => signBytes(t2b(text)),
signTextHex: text => b2h(signBytes(t2b(text))),
...
@crypto-coder writes
What do we still need for an npm package?
Nothing, as far as I'm concerned. That is: publishing via npm is orthogonal to adding / changing the feature set.
On the other hand, I'm content with publishing via github for now, so maybe somebody else who is more inclined to do the publishing should weigh in.
@crypto-coder writes:
What do we have that we don't need for an npm package?
Nothing.
All of the stuff we have added has been well motivated, I think.
Final list for first version of the NPM package -
Connect to RNode: var myNode = RNode(grpc {hostname, port}); Deploy SmartContract: myNode.doDeploy( DeployData, commit_block=false ); Commit trans to Block: myNode.createBlock( ); Get Block by hash: myNode.getBlock( hash ); Get all Blocks: myNode.getAllBlocks( block_depth ); Get Data by Par: myNode.listenForDataAtName( par ); Hash Data (SHA256): myNode.sha256Hash( js_data ); Hash Data (Keccak256): myNode.keccak256Hash( js_data ); Hash Data (Blake2b256): myNode.blake2b256Hash( js_data );
Since my time is scarce after today, I went ahead and reviewed https://github.com/crypto-coder/rchain-api/tree/npm in advance of the PR. I did find several critical issues.
We shipped on time! https://www.npmjs.com/package/rchain-api 0.7.1-beta.1 b9a4636
Oh. I was going to close this but I can't.
Awesome work everybody, especially @dckc and @crypto-coder . Thanks to you we have our first published package! https://www.npmjs.com/package/rchain-api
From @crypto-coder on October 3, 2018 6:49
Need to reorganize RChain-API for NPM. Package name would be "rchain.js".
Installation using NPM: npm install --save rchain Inclusion in Node.js: const { RNode, RCore } = require('rchain'); Inclusion in Typescript: import { RNode, RCore } from 'rchain';
Initial function set would include:
Copied from original issue: JoshOrndorff/RChain-API#19