Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add /wallet/:id/tx http call #465

Closed
wants to merge 1 commit into from
Closed

Add /wallet/:id/tx http call #465

wants to merge 1 commit into from

Conversation

qix
Copy link

@qix qix commented Jun 3, 2020

At the moment it is not possible to create a single transaction with multiple bids (or multiple opens.) This creates a new RPC endpoint that allows the caller to pass in an array of bids. The bids are specified exactly the same as the bid endpoint requires them.

This should be extendable to allow opens, reveals, and all other covenant types to be specified in a later change.

I have not heavily tested this change, but have verified that it works. If the approach is correct I can add some test cases.

Copy link
Contributor

@tynes tynes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this functionality is redundant and can be accomplished with endpoints that already exist.

Note that POST body can include an outputs array of objects that represent each output, and a covenant JSON property can be included in the output object.

hsd/lib/wallet/http.js

Lines 1642 to 1653 in 22be7fa

if (valid.has('outputs')) {
const outputs = valid.array('outputs');
for (const output of outputs) {
const valid = new Validator(output);
let addr = valid.str('address');
if (addr)
addr = Address.fromString(addr, this.network);
let covenant = valid.obj('covenant');


// @todo: Is this safe without a lock around it? What needs and does not need locks isn't
// super clear.
outputs.push(await req.wallet.makeBidOutput(name, bid, lockup, options.account || 0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: separate this into multiple lines instead of using ||

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, was just copying the style that's used in the codebase.

Things would be much easier with prettier/typescript, but that's a separate issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint is used for this project, you can see the configuration here:
https://github.com/handshake-org/hsd/blob/master/.eslintrc.json

@tynes
Copy link
Contributor

tynes commented Jun 4, 2020

@qix Are you able to accomplish what you would like with the endpoints mentioned in #465 (review)?

@qix
Copy link
Author

qix commented Jun 4, 2020

Yeah sorry about the delay. Not sure how I missed that earlier, happy to close this one out.

It's a little unfortunate that the wallet tx API requires a lot more handshake protocol specifics, but I can make it work. In any case this change would be much neater/shorter by adding a bids option to the existing endpoint.

@qix qix closed this Jun 4, 2020
@qix
Copy link
Author

qix commented Jun 5, 2020

@tynes re-opening this because the user experience of the other API is far from ideal.

I'm of the opinion that the ability to send multiple bids in a transaction is a useful API for a wallet. While I could go ahead and implement my own wallet (perhaps using hsd as a library), I'd rather build on top of the hsd API.

Trying to send a transaction using /create was painful for lack of a better word. The actual details for the outputs parameter is not documented, and errors simply result in a AssertionError response from the server.

To focus on the issue at hand after some time trying to get it to work this is the call I came up with:

curl -X POST -d '{"subtractFee":false,"outputs":[
  {"address":getnewaddress,"covenant":{
    "type":3,
    "items":[hash from nameinfo, height ,name, bid],
    "value":total
  }}
],"passphrase":"..."}' -D - http://localhost:12039/wallet/primary/create

There is a lot there that is API specific, and requires multiple calls to the RPC to fetch the address and the nameHash.

Instead I propose an extension to /create, which would allow you to send in certain types of covenants in the expected form:

curl -X POST -d '{"subtractFee":false,"bids":[
  {"name":name, "bid":bid, "lockup":lockup}, ...
],"passphrase":"..."}' -D - http://localhost:12039/wallet/primary/create

That frees the user from having to know protocol specifics (bid = type 3), generating the hashes or fetching them from the API, understanding the height parameter of the covenant (honesty haven't had a chance to read about what that should be set to), or similar concerns.

I'm happy to implement it, believe that change would be shorter than the diff here.

@qix qix reopened this Jun 5, 2020
@pinheadmz
Copy link
Member

pinheadmz commented Jun 5, 2020

I think you're on the right track @qix and you're right the create API requires the user to retrieve data the wallet usually handles on its own. The one thing I don't like about your proposed example is the "bids" key in the JSON -- will every request have to have this key-vaue? What if I want to send an array of a different covenant type?

This reminds me of sendreveal and sendredeem -- both of which (if no name is specified as argument) check the wallet for all bids or reveals and sends one big TX with a bunch of REVEAL or REDEEM otputs.

So, maybe what would suit your use case best is a very specific new rpc sendbids or sendmultiplebids something like this:

hsw-rpc sendmultiplebids '{"foo": [1, 2], "bar": [4, 4], "baz": [3, 4]}'

an object where keys are names and values are an array of [bid, lockup]

If the usecase calls for it, maybe similar rpc sendopens or sendmultlipleopens can be added as well

@tynes
Copy link
Contributor

tynes commented Jun 5, 2020

Instead I propose an extension to /create, which would allow you to send in certain types of covenants in the expected form

I think that this is an interesting idea, what do you think about generalizing it so that it can create a transaction with arbitrary opens, bids or reveals? Technically all of the covenant types could be included, but that increases the complexity.

@qix
Copy link
Author

qix commented Jun 5, 2020

That's why I suggested adding it to a more generic endpoint. I imagined bids being optional, and if provided it is appended to outputs.

That way support for reveals, opens, or any other covenant types could be added in the future as well.

@qix
Copy link
Author

qix commented Jun 5, 2020

I'm somewhat against the sendmultiplebids proposal, because there is already a lot of duplicate boilerplate code for each of the sendX methods. I'm looking for a slightly lower level API here, but not one that requires a deep understanding of the protocol.

@pinheadmz
Copy link
Member

maybe it can be complexified:

hsw-rpc sendmultiple \
 '{"OPEN": ["foo", "bar", "baz"], "BID": [{"example": [10, 20]}, {"cats": [1, 1]}]}'

@qix
Copy link
Author

qix commented Jun 5, 2020

Works for me if that's the approach you all want.

I prefer the HTTP api for extensibility reasons (adding another type of BID to that would be extremely messy), but it'll work for what I need right now.

I do think the arguments to sendbid should match the array in BID: [], so I'd prefer "BID": [["example", 10, 20], ["cats", 1, 1]]. Alternatively "BID": {"example": [10, 20], "cats": [1, 1]}

@randomlogin
Copy link

I think the most useful approach is the most general and implements all output types. The current endpoint allows to send arbitrary output types, but the user has to enter all covenant items, like sha3 of the name or its hex encoding. All this data can be added by the node.

What do you think of sendmany [["BID", name, bid, blind], ["OPEN", name], ["UPDATE", [record]], etc.

I fell that more natural would be to use sendmany, but currently it has other syntax. Then there should be a good reason to have several 'send multiple' endpoints.

@qix
Copy link
Author

qix commented Jul 19, 2020

That looks good to me too, but to be honest I'm not planning on investing more time in this project so going to sit out of further discussion.

@pinheadmz
Copy link
Member

What do you think of sendmany [["BID", name, bid, blind], ["OPEN", name], ["UPDATE", [record]], etc.

I think this looks the best and is the most obvious. the arguments following each covenant type would match the send____() for that type. I think this would be best implemented in the wallet rpc, where _validate____() methods can do "client side" checking before sending to the wallet. What would we call it? rpc sendmanynames I think?

So then in wallet/rpc.js we add that call, with a switch statement for each covenant type that checks with the rpc _validateBid() for each set of args. Once validated the whole mess gets passed to a new method in wallet.js that creates new MTX() and then switches through covenant types again and passes the same MTX to each make___() method in wallet.js.

Then each of those make___() methods take a new optional argument, which is an MTX. If none is present, they continue like normal: create a new MTX() and add one covenant to it:

from makeBid():

hsd/lib/wallet/wallet.js

Lines 1699 to 1711 in a3049d5

const output = new Output();
output.address = addr;
output.value = lockup;
output.covenant.type = types.BID;
output.covenant.pushHash(nameHash);
output.covenant.pushU32(start);
output.covenant.push(rawName);
output.covenant.pushHash(blind);
const mtx = new MTX();
mtx.outputs.push(output);
return mtx;

@pinheadmz
Copy link
Member

closing this in favor of #627

Thank you @qix !!

@pinheadmz pinheadmz closed this Aug 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants