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

multi: add support for ZCash #1570

Merged
merged 6 commits into from
Jun 13, 2022
Merged

multi: add support for ZCash #1570

merged 6 commits into from
Jun 13, 2022

Conversation

buck54321
Copy link
Member

@buck54321 buck54321 commented Apr 7, 2022

Implement block deserialization, tx deserialization/serialization
and input signing for ZCash and generalize those functions in the
client and server btc packages.

Implemenation notes
  1. zcashd does not support encrypted wallets. No passwords allowed.
  2. After starting the harness, it takes a few minutes for beta to
     get caught up.
  3. zcashd can take a very long time to get it's fee estimates primed.

@buck54321
Copy link
Member Author

Might want to keep an eye on https://github.com/zcash/lightwalletd too for a possible built-in light wallet. It doesn't appear to be suitable as is, but not certain.

@chappjc
Copy link
Member

chappjc commented Apr 25, 2022

Will review shorty. Wanna rebase away the first two commits that are already merged (the first one without the ExchangeWalletFullNode override)?

Copy link
Contributor

@martonp martonp left a comment

Choose a reason for hiding this comment

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

Looks good, I was able to do a swap on simnet. Haven't tested with testnet yet. For some reason the dex client is constantly sending getbestblockhash, getnetworkinfo, and getblockchaininfo calls to the zcash client when I'm running on simnet. It seems a bit excessive.. there are at least 2-3 calls every second.

client/asset/btc/btc.go Outdated Show resolved Hide resolved
serializeTx func(*wire.MsgTx) ([]byte, error)
deserializeBlock func([]byte) (*wire.MsgBlock, error)
hashTx func(*wire.MsgTx) *chainhash.Hash
numericGetRawTxRPC bool
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use a doc saying this rpc method has different args in zcash.

dex/networks/zec/block.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
dex/testing/zec/harness.sh Outdated Show resolved Hide resolved
Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

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

Some thoughts on sign.go to start

client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
// https://github.com/zcash/zips/blob/main/zip-0243.rst#specification
// which extends https://zips.z.cash/zip-0143#specification
// See also implementation @
// https://github.com/iqoption/zecutil/blob/master/sign.go
Copy link
Member

@chappjc chappjc May 11, 2022

Choose a reason for hiding this comment

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

This sign.go file needs a license comment at the top. It's unfortunate that zecutil completely threw away bchutil's license, and double unfortunate that libzec-go is gpl. I think with some minor rewriting and using our own code style and idioms to make this properly ours we're good though. It's a short function

client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
client/asset/zec/sign.go Outdated Show resolved Hide resolved
Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

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

dex/networks/zec

dex/networks/zec/addr.go Outdated Show resolved Hide resolved
dex/networks/zec/addr.go Outdated Show resolved Hide resolved
dex/networks/zec/addr.go Outdated Show resolved Hide resolved
dex/networks/zec/block.go Outdated Show resolved Hide resolved
dex/networks/zec/block.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
go.mod Show resolved Hide resolved
dex/networks/zec/params.go Outdated Show resolved Hide resolved
dex/networks/zec/block_test.go Outdated Show resolved Hide resolved
client/asset/btc/btc.go Outdated Show resolved Hide resolved
@buck54321
Copy link
Member Author

Updated for NU5. I expect that ZCash won't be live on DEX when the upgrade goes live on May 31st, but we're ready-ish for the upgrade if it is. For a ZCash upgrade, an operator should be expected to shut down for the upgrade, since old version txs won't be accepted on the new chain, per this upgrade guide.

I'm syncing testnet and then I'll search for some NU5 txs to use for tests.

@buck54321
Copy link
Member Author

For some reason the dex client is constantly sending getbestblockhash, getnetworkinfo, and getblockchaininfo calls to the zcash client when I'm running on simnet. It seems a bit excessive.. there are at least 2-3 calls every second.

I put some feelers in, and it seems to me like the calls to getbestblockhash are our normal block polling. I'm not sure why we're seeing two log messages for each in the zcashd/bitcoind terminals. Might be worth looking into further, but I don't see any issues on the client side.

The getnetworkinfo is coming from our monitorPeers loop.

I'm not seeing a lot of getblockchaininfo, but that would be expected with a new block.

I do see some estimatesmartfee pretty regularly from (*Core).tick(*Core).cacheRedemptionFeeSuggestion. Related: #1515.

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

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

Looks great! 🚀 🔒 🎆

Just need a resolve.

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

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

Wow. Thats a lot of zcash. My eyes started to glaze over at tx.go

I've not been able to trade so far with :

2022-05-19 23:23:46.860 [ERR] CORE: notify: |ERROR| (order) Swap send error - Error encountered sending a swap output(s) worth 1.00000000 ZEC on order 117411dd - Order: 117411dd464a5b5f40e3fc40c32f5d45cf0fbc88d1fa38fca69ab9ec668b1090
2022-05-19 23:23:46.860 [ERR] CORE: 127.0.0.1:17273 tick: {swapMatches order 117411dd464a5b5f40e3fc40c32f5d45cf0fbc88d1fa38fca69ab9ec668b1090 - {error sending swap transaction: signing error: tx signing error: rawrequest (signrawtransaction) error: -22: TX decode failed, raw tx: 0500000001ce67eab2739d1db57d16dcc8457cd0f1028c424459a5052ef4d65ca59cf841150100000000ffffffff0100e1f5050000000017a914c83a74347ff867cade02a48197b39345b8635b018700000000}}

I also attempted to get the core simnet tests running but they failed. Can do in another pr though.

Noticed a couple things maybe unrelated to this pr.

If I start to make a ZEC wallet but I put in a password, it errors, which is fine. But if I close that box then I see this for the wallet:
image

And I can click on that box to unlock the wallet that isnt there.

Also, I was not able to pay the fee with bitcoin for the simnet tests. May be a problem with the simnet tests.

$ zcashd --version
Zcash Daemon version v5.0.0

dex/testing/zec/harness.sh Show resolved Hide resolved
dex/testing/zec/harness.sh Outdated Show resolved Hide resolved

func validateSigHashType(v txscript.SigHashType) bool {
return v == txscript.SigHashAll || v == txscript.SigHashNone || v == txscript.SigHashSingle ||
v == txscript.SigHashAnyOneCanPay || v == 0x82 || v == 0x83
Copy link
Member

Choose a reason for hiding this comment

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

What are these last two hex?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can't seem to figure it out, but I'm basing it on

Consensus rule: [NU5 onward] Any SIGHASH type encoding used in a version 5 transaction MUST be the
canonical encoding of one of the defined SIGHASH types, i.e. one of 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83.

from https://zips.z.cash/protocol/protocol.pdf

Copy link
Member

@chappjc chappjc May 19, 2022

Choose a reason for hiding this comment

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

Would that be the bit-or of SIGHASH_ANYONECANPAY with either SIGHASH_NONE or SIGHASH_SINGLE?

/** Signature hash types/flags */
enum
{
    SIGHASH_ALL = 1,
    SIGHASH_NONE = 2,
    SIGHASH_SINGLE = 3,
    SIGHASH_ANYONECANPAY = 0x80,
};

Now that I say that, I think we're missing 0x81 too (SIGHASH_ALL | SIGHASH_ANYONECANPAY)?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, and just SigHashAnyOneCanPay isn't valid it seems. It's gotta be combined with one of the all/none/single options: https://github.com/zcash/zcash/blob/a45c2a2d4e3d387bf2dcb2e5808db2f6f7008799/src/script/interpreter.cpp#L1237-L1257

dex/networks/btc/clone.go Outdated Show resolved Hide resolved
@chappjc
Copy link
Member

chappjc commented May 19, 2022

Oh! zcash 5.0 was released a week ago. https://github.com/zcash/zcash/releases/tag/v5.0.0 I've been working with 4.6

go.mod Outdated Show resolved Hide resolved
@chappjc
Copy link
Member

chappjc commented May 19, 2022

How about https://zcashblockexplorer.com/ for the mainnet explorer? No external JS, displays fine with no JS, seems to be reference deployment of https://github.com/nighthawk-apps/zcash-explorer, has an onion address, NU5 tx and UA support

I don't see a good testnet option though. Maybe https://sochain.com/testnet/zec

dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Outdated Show resolved Hide resolved
dex/networks/zec/tx.go Show resolved Hide resolved
@chappjc
Copy link
Member

chappjc commented May 22, 2022

#1597 made some conflicts

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

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

This server log seems off: Blocks are too empty to calculate %!d(string=zec) median fees. Using no-competition rate.

Also, I can't seem to get refunds to happen. Is client checking the locktime correctly?

It looks like will need a couple more wallets for simnet tests just like doge. Would you like to add or shall I?

Comment on lines +49 to +68
// Tx can only produce tx hashes for unshielded transactions. Tx can only create
// signature hashes for unshielded version 5 transactions.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe first Tx can only produce tx hashes for unshielded transactions. is redundant.

ConsensusBranchHeartwood = [4]byte{0x0B, 0x23, 0xB9, 0xF5} // 903000
ConsensusBranchCanopy = [4]byte{0xA6, 0x75, 0xFF, 0xE9} // 1046400, tesnet: 1028500
ConsensusBranchNU5 = [4]byte{0xB4, 0xD0, 0xD6, 0xC2} // 1687104, testnet: 1842420
ConsensusBranchNU5 = [4]byte{0xB4, 0xD0, 0xD6, 0xC2} // 1687104, testnet: 1842420
Copy link
Member

Choose a reason for hiding this comment

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

Exported bytes probably better as a constant so that they cannot be mutated.

copy(b[:32], prevoutsDigest[:])
copy(b[32:64], seqDigest[:])
copy(b[64:], outputsDigest[:])
return blake2bHash(b, []byte("ZTxIdTranspaHash"))
Copy link
Member

Choose a reason for hiding this comment

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

Could make some of these strings that are reused constants to avoid typos. I don't see any typos currently.

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

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

OK. Just one silly conflict with the new txscript.NewTxSigHashes function signature. Also @JoeGruffins review

"base": "ZEC_simnet",
"quote": "BTC_simnet",
"lotSize": 100000000,
"rateStep": 100000,
Copy link
Member

@chappjc chappjc May 31, 2022

Choose a reason for hiding this comment

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

This rate step is too high to reflect realistic rates. No a big deal on simnet, just not realistic.
Currently it's 0.00293146 BTC/ZEC, but I can only use 0.00x

@chappjc
Copy link
Member

chappjc commented May 31, 2022

Also, I can't seem to get refunds to happen. Is client checking the locktime correctly?

@JoeGruffins is right. It can never refund. It seems the reason is that the getblockheader response does not include MedianTime, so it is always treated as 0 in (*baseWallet).LocktimeExpired and thus cannot ever be after contract expiry.

$  ./alpha getblockheader 0b5d2de16ab1f74674f4ad52f2096d90a293c61b9e552c49433a33fafc9541a9
{
  "hash": "0b5d2de16ab1f74674f4ad52f2096d90a293c61b9e552c49433a33fafc9541a9",
  "confirmations": 1,
  "height": 427,
  "version": 4,
  "merkleroot": "0abafddb3bd8053a633e64a50e7876b663371c328e7f31036524a23dccf5fb4e",
  "finalsaplingroot": "3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb",
  "time": 1654015360,
  "nonce": "00005ab9fbe1195127e17d82a2929c18e0c5037e44836c4a2d3ccdf7ef2c002e",
  "solution": "0c6203f9b1fd8888ab255da63a4435b577c910339676e1a30d45cc3cba2fd9f4b45e95b6",
  "bits": "200f0f0f",
  "difficulty": 1,
  "chainwork": "0000000000000000000000000000000000000000000000000000000000001c6c",
  "previousblockhash": "05a282582126e141821e885428d852e5756a471bacc122aec282392fcca4cc2b"
}

@chappjc
Copy link
Member

chappjc commented May 31, 2022

I suppose we'll just have to pull the last 11 block headers to compute mediantime. The only RPCs I can see that might give it to us is getblockdeltas, which requires some crazy switches like -insightexplorer, or getblocktemplate->mintime-1, and it's probably a terrible idea to use mining functions.

BTW, refunds do work if I hack the expiry check:

2022-05-31 12:05:21.005 [DBG] CORE: Refundable match 5010ba73c1a55f3b5a7bebcbf08072e7c72a3f286ef3714af7da9ba5ffb471d9 for order 4d6f2b0b33d6040b943f020b5ce43930c978ff8ad4f606ef468ec5295b28d166 (Maker)
2022-05-31 12:05:21.005 [INF] CORE: Refunding zec contract 94565e2e3933e0a3c1d081b352bc3114e468eb72fe6b66a6a96e83f55a4258d8:0 for match 5010ba73c1a55f3b5a7bebcbf08072e7c72a3f286ef3714af7da9ba5ffb471d9 (no valid counterswap received from Taker)
2022-05-31 12:05:21.006 [TRC] CORE[zec]: Failed to get fee rate: fee could not be estimated
2022-05-31 12:05:21.007 [TRC] CORE[zec]: no 2-conf feeRate available: fee could not be estimated
2022-05-31 12:05:21.007 [TRC] CORE[zec]: feeRateWithFallback using caller's suggestion for fee rate, 10. Local estimate unavailable
2022-05-31 12:05:21.011 [WRN] CORE: notify: |WARNING| (order) Matches Refunded - Refunded 1.00000000 ZEC on order 4d6f2b0b - Order: 4d6f2b0b33d6040b943f020b5ce43930c978ff8ad4f606ef468ec5295b28d166

Implement block deserialization, tx deserialization/serialization
and input signing for ZCash and generalize those functions in the
client and server btc packages.

Implemenation notes
  1. zcashd does not support encrypted wallets. No passwords allowed.
  2. After starting the harness, it takes a few minutes for beta to
     get caught up.
  3. zcashd can take a very long time to get it's fee estimates primed.
All txs we create and sign must be version 5. Use new SIGHASH
algos from ZIP-244. Move SIGHASH stuff to methods of dexzec.Tx.

Add live test to scan testnet blocks looking for deserialization
errors.
Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

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

Latest updates look good. Refunds work now.

[DBG] CORE: Refundable match 4092328257640b9120a1384debe25b6b185acec21b24f6e1711cd4a1d47649d6 for order 72f905d3dfc7a504b7fff74e79d80318295aa8f472107d19c9c65d9e52d25dd5 (Maker)
[INF] CORE: Refunding zec contract bd12551965edd38fbc1aa1c8cfd5fdec42f48bae92bff6b15f4494adf36db9d6:0 for match 4092328257640b9120a1384debe25b6b185acec21b24f6e1711cd4a1d47649d6 (no valid counterswap received from Taker)

@chappjc chappjc merged commit f6cccaa into decred:master Jun 13, 2022
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