-
Notifications
You must be signed in to change notification settings - Fork 92
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 Bitcoin Cash #944
Conversation
type AuditInfo struct { | ||
// Recipient is the string-encoded recipient address. | ||
Recipient() string | ||
Recipient string | ||
// Expiration is the unix timestamp of the contract time lock expiration. | ||
Expiration() time.Time | ||
Expiration time.Time | ||
// Coin is the coin that contains the contract. | ||
Coin() Coin | ||
Coin Coin | ||
// Contract is the contract script. | ||
Contract() dex.Bytes | ||
Contract dex.Bytes | ||
// SecretHash is the contract's secret hash. | ||
SecretHash() dex.Bytes | ||
SecretHash dex.Bytes | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed to modify the Recipient
outside of client/asset/btc, so making this a field was a solution, but I didn't see any reason that any of these needed to be methods.
if err != nil { | ||
return nil, fmt.Errorf("error decoding sender address %s: %w", sender, err) | ||
} | ||
func MakeContract(rAddr, sAddr btcutil.Address, secretHash []byte, lockTime int64, segwit bool, chainParams *chaincfg.Params) ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing these arguments from string
to btcutil.Address
was needed to make things work with the new customizable AddressDecoder
. It also appears to be a simplification when the changes are taken as a whole.
if contract.RefundAddress() != swap.refund.String() { | ||
t.Fatalf("case 13 - wrong recipient. wanted '%s' got '%s'", contract.RefundAddress(), swap.refund.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RefundAddress
method remained unused, so I didn't replicate it as a field. Can always add it later.
client/asset/btc/btc.go
Outdated
@@ -361,6 +382,10 @@ type ExchangeWallet struct { | |||
useSplitTx bool | |||
useLegacyBalance bool | |||
segwit bool | |||
legacyRawFeeLimit bool | |||
signNonSegwit TxInSigner | |||
estimateFee func(RPCClient, uint64) (uint64, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious why you went the way of a function rather than a switch or bool as we've been doing for other asset differences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bch rpc for estimatefee
is not the same as the legacy bitcoind estimatefee
rpc. The bitcoin RPC at least took a confirmation target argument. Since it's not a difference between legacy/non-legacy, I figured a custom function is better.
// Verify contract and set refundAddress and swapAddress. | ||
err = btc.auditContract(contract) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return contract, nil | ||
return btc.auditContract(output) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Big thumbs up for the much clearer semantics here.
Just flagged this work for the 0.3 milestone, but I don't see why it can't be merged with the 0.2 release as an experimental and/or in-progress feature, perhaps just without full support for production mainnet use. |
b3a701d
to
a121002
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unable to run tests or set up a wallet with this error:
error creating bch wallet: error getting wallet balance for bch: rawrequest error: -32601: Method not found
livetest.go:160: error getting available: rawrequest error: -32601: Method not found
Could you add the info about what to name executables and being careful not to erase bitcoin's datadir to a README.md in the dex/testing/bch folder?
Should be fixed now @JoeGruffins . Lost something in a rebase. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working well on simnet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reads great, but still testing. Just a few nits for now.
I'm happy to see the deinterfacing of both AuditInfo and Contract as it simplifies things and makes code dealing with those much more transparent.
dex/networks/bch/params.go
Outdated
// TestNet3Params are the clone parameters for testnet. | ||
TestNet3Params = btc.ReadCloneParams(&btc.CloneParams{ | ||
PubKeyHashAddrID: bchchaincfg.TestNet3Params.LegacyPubKeyHashAddrID, | ||
ScriptHashAddrID: bchchaincfg.TestNet3Params.LegacyScriptHashAddrID, | ||
Bech32HRPSegwit: "bchtest", | ||
CoinbaseMaturity: 100, | ||
Net: 0xf4f3e5f4, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just reiterating what I mentioned in matrix chat - we might consider making testnet4 our preferred testnet.
https://bitcoincashresearch.org/t/testnet4-and-scalenet/148
https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/merge_requests/739#note_399231913
The main testnet for BCH, testnet3, has gotten bloated. People have used it for testing 32 MB block propagation for weeks on end. As a result, testnet3 now takes a long time to sync and is kinda annoying to work with. I think the problem here is that we’ve had two separate use cases for a testnet which don’t mesh well. I think we would be better served if we replaced testnet3 with two separate nets.
testnet4 is optimized for convenience. It’s intended to be kept lightweight and quick to sync. Its main purpose is for compatibility testing and feature testing. ...
Also nice about testnet4 is that it has unique default ports like 28333
Explorer: though https://tbch4.loping.net/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I started switching everything to testnet 4, but quickly ran into some hurdles because we're using the bchd chaincfg.Params
in a few places, and no such Params
exist for testnet4. The clone params are easy and I know exactly which fields are being used there, but I can't say the same for the bchd paths, so we can't use the partial params like we do with clone params.
Can still do it, but punting for now. We should consider opening a PR at bchd with the new parameters too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Was really just taking notes on testnet4 here.
ScriptHashAddrID: bchchaincfg.TestNet3Params.LegacyScriptHashAddrID, | ||
Bech32HRPSegwit: "bchtest", | ||
CoinbaseMaturity: 100, | ||
Net: 0xf4f3e5f4, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Net becomes 0xe2b7daaf
on testnet4
https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/blob/a5e1d83f308f0428b401816b113e9cf3fd1ecb03/src/chainparams.cpp#L478
dex/networks/bch/params.go
Outdated
PubKeyHashAddrID: bchchaincfg.TestNet3Params.LegacyPubKeyHashAddrID, | ||
ScriptHashAddrID: bchchaincfg.TestNet3Params.LegacyScriptHashAddrID, | ||
Bech32HRPSegwit: "bchtest", | ||
CoinbaseMaturity: 100, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These four appear same on testnet4, https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/blob/a5e1d83f308f0428b401816b113e9cf3fd1ecb03/src/chainparams.cpp#L499-500 (6f and c4)
New conflicts with fee-estimate merged. |
The primary challenge is that Bitcoin Cash uses a special address encoding called Cash Address that encodes a pubkey hash using Bech32, but does not signify segwit. Another challenge is that the Bitcoin Cash uses a different signature hash algorithm. Bitcoin Cash also doesn't implement estimatesmartfee. The closest thing they have is estimatefee, and their version takes no confirmation target argument. I'll look more into how the algo works. Similar to Litecoin, Bitcoin has not yet implemented the new sendrawtransaction argument signature, and still uses the older allowHighFees bool arguement. To solve these challenges, I've made liberal use of the github.com/gcash/bchd and github.com/gcash/bchutil packages, which appears to be under active maintenance. Regardless, the functionality we use is likely to be battle-tested at this point, so I think we're good to go. IMPORTANT: Bitcoin Cash uses the same data directory, ~/.bitcoin, and the same executable names, bitcoind and bitcoin-cli. This makes life very difficult for both developers and users. 1. DO NOT start Bitcoin Cash without specifying a custom -datadir. IF YOU FAIL to specify a custom data directory, your Bitcoin Core data will be destroyed and YOU'LL HAVE TO RESYNC BITCOIN. 2. Many of our simnet scripts rely on our executables being in PATH. For dcrdex developement, it is expected that the executables (or symlinks) are named bitcoincashd and bitcoincash-cli.
client/asset/btc/btc.go
Outdated
var rpcErr *dcrjson.RPCError | ||
if errors.As(err, &rpcErr) && rpcErr.Code == dcrjson.ErrRPCMethodNotFound.Code { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to circle back on this, but I believe we should be using the constants in btcjson, although clearly we'd need to assert with dcrjson.RPCError
because of our using dcr's rpcclient now. Either that or we just make a package level const with the expected value of ErrRPCMethodNotFound.Code
to spare us importing btcjson just for one number. Just that the error codes between dcr and btc's rpc servers aren't necessarily the same, and I've noted commits with bitcoin where they've actually changed the codes and I'm sure we didn't change them too.
server/asset/bch/live_test.go
Outdated
if err != nil { | ||
fmt.Printf("Connect failed: %v", err) | ||
return 1 | ||
} | ||
defer wg.Wait() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look like it's going to start waiting before cancelling now when m.Run()
completes because this defer is on the top of the defer stack. When looking at the previous revision where I had requested a change, I had envisioned moving the ctx, cancel := context.WithCancel(context.Background())
down to right before dexAsset.Connect(ctx)
because ctx
isn't used before that, thus allowing the cancel(); wg.Wait()
to go in the same closure again, just down here. If Connect
failed, you'd still have to cancel manually before return 1
, or just leak the context because who cares TestMain
is about to terminate.
Add server and client support for Bitcoin Cash.
The primary challenge is that Bitcoin Cash uses a special address encoding called Cash Address that encodes a pubkey hash using Bech32, but does not signify segwit. Another challenge is that the Bitcoin Cash uses a different signature hash algorithm.
Bitcoin Cash also doesn't implement
estimatesmartfee
. The closest thing they have isestimatefee
, and their version takes no confirmation target argument. I'll look more into how the algo works.Similar to Litecoin, Bitcoin has not yet implemented the new
sendrawtransaction
argument signature, and still uses the olderallowHighFees bool
argument.To solve these challenges, I've made liberal use of the github.com/gcash/bchd and github.com/gcash/bchutil packages, which appears to be under active maintenance. Regardless, the functionality we use is likely to be battle-tested at this point, so I think we're good to go.
IMPORTANT: Bitcoin Cash uses the same data directory,
~/.bitcoin
, and the same executable names,bitcoind
andbitcoin-cli
, as Bitcoin Core. This makes life very difficult for both developers and users.-datadir
. IF YOU FAIL to specify a custom data directory, your Bitcoin Core data will be destroyed and YOU'LL HAVE TO RESYNC BITCOIN.Avoid overwriting your Bitcoin block data by adding
networkactive=1
to your .bitcoin/bitcoin.conf.1
is the default value, but Bitcoin Cash doesn't support the setting, so will error if you forget to specify a customdatadir
.PATH
. For dcrdex developers, it is expected that the executables (or symlinks) are namedbitcoincashd
andbitcoincash-cli
. The live tests on the server backend also expect your mainnet directory to be at ~/.bch.