Skip to content

Commit 0fbe5bf

Browse files
committed
Add support for Zcoin
1 parent 56a1158 commit 0fbe5bf

12 files changed

+262
-9
lines changed

chain/zcoin/.zcoin.go.swp

12 KB
Binary file not shown.

chain/zcoin/.zcoin_suite_test.go.swp

12 KB
Binary file not shown.

chain/zcoin/.zcoin_test.go.swp

16 KB
Binary file not shown.

chain/zcoin/zcoin.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package zcoin
2+
3+
import (
4+
"github.com/renproject/multichain/chain/bitcoin"
5+
"github.com/renproject/multichain/compat/bitcoincompat"
6+
)
7+
8+
// NewTxBuilder returns an implementation of the transaction builder interface
9+
// from the Bitcoin Compat API, and exposes the functionality to build simple
10+
// Zcoin transactions.
11+
func NewTxBuilder() bitcoincompat.TxBuilder {
12+
return bitcoin.NewTxBuilder()
13+
}
14+
15+
// The Tx type is copied from Bitcoin.
16+
type Tx = bitcoin.Tx

chain/zcoin/zcoin_suite_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package zcoin_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestZcoin(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Zcoin Suite")
13+
}

chain/zcoin/zcoin_test.go

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package zcoin_test
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"reflect"
8+
"time"
9+
10+
"github.com/btcsuite/btcd/chaincfg"
11+
"github.com/btcsuite/btcutil"
12+
"github.com/renproject/id"
13+
"github.com/renproject/multichain/chain/zcoin"
14+
"github.com/renproject/multichain/compat/bitcoincompat"
15+
"github.com/renproject/pack"
16+
17+
. "github.com/onsi/ginkgo"
18+
. "github.com/onsi/gomega"
19+
)
20+
21+
var _ = Describe("Zcoin", func() {
22+
Context("when submitting transactions", func() {
23+
Context("when sending XZC to multiple addresses", func() {
24+
It("should work", func() {
25+
// Load private key, and assume that the associated address has
26+
// funds to spend. You can do this by setting ZCOIN_PK to the
27+
// value specified in the `./multichaindeploy/.env` file.
28+
pkEnv := os.Getenv("ZCOIN_PK")
29+
if pkEnv == "" {
30+
panic("ZCOIN_PK is undefined")
31+
}
32+
wif, err := btcutil.DecodeWIF(pkEnv)
33+
Expect(err).ToNot(HaveOccurred())
34+
35+
// PKH
36+
pkhAddr, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeCompressed()), &chaincfg.RegressionNetParams)
37+
Expect(err).ToNot(HaveOccurred())
38+
pkhAddrUncompressed, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &chaincfg.RegressionNetParams)
39+
Expect(err).ToNot(HaveOccurred())
40+
log.Printf("PKH %v", pkhAddr.EncodeAddress())
41+
log.Printf("PKH (uncompressed) %v", pkhAddrUncompressed.EncodeAddress())
42+
43+
// Setup the client and load the unspent transaction outputs.
44+
client := bitcoincompat.NewClient(bitcoincompat.DefaultClientOptions().WithHost("http://127.0.0.1:19232"))
45+
outputs, err := client.UnspentOutputs(context.Background(), 0, 999999999, pkhAddr)
46+
Expect(err).ToNot(HaveOccurred())
47+
Expect(len(outputs)).To(BeNumerically(">", 0))
48+
output := outputs[0]
49+
50+
// Check that we can load the output and that it is equal.
51+
// Otherwise, something strange is happening with the RPC
52+
// client.
53+
output2, _, err := client.Output(context.Background(), output.Outpoint)
54+
Expect(err).ToNot(HaveOccurred())
55+
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())
56+
57+
// Build the transaction by consuming the outputs and spending
58+
// them to a set of recipients.
59+
recipients := []bitcoincompat.Recipient{
60+
{
61+
Address: pkhAddr,
62+
Value: pack.NewU64((output.Value.Uint64() - 1000) / 2),
63+
},
64+
{
65+
Address: pkhAddrUncompressed,
66+
Value: pack.NewU64((output.Value.Uint64() - 1000) / 2),
67+
},
68+
}
69+
tx, err := zcoin.NewTxBuilder().BuildTx([]bitcoincompat.Output{output}, recipients)
70+
Expect(err).ToNot(HaveOccurred())
71+
72+
// Get the digests that need signing from the transaction, and
73+
// sign them. In production, this would be done using the RZL
74+
// MPC algorithm, but for the purposes of this test, using an
75+
// explicit privkey is ok.
76+
sighashes, err := tx.Sighashes()
77+
signatures := make([]pack.Bytes65, len(sighashes))
78+
Expect(err).ToNot(HaveOccurred())
79+
for i := range sighashes {
80+
hash := id.Hash(sighashes[i])
81+
privKey := (*id.PrivKey)(wif.PrivKey)
82+
signature, err := privKey.Sign(&hash)
83+
Expect(err).ToNot(HaveOccurred())
84+
signatures[i] = pack.NewBytes65(signature)
85+
}
86+
Expect(tx.Sign(signatures, pack.NewBytes(wif.SerializePubKey()))).To(Succeed())
87+
88+
// Submit the transaction to the Zcoin node. Again, this
89+
// should be running a la `./multichaindeploy`.
90+
txHash, err := client.SubmitTx(context.Background(), tx)
91+
Expect(err).ToNot(HaveOccurred())
92+
log.Printf("TXID %v", txHash)
93+
94+
for {
95+
// Loop until the transaction has at least a few
96+
// confirmations. This implies that the transaction is
97+
// definitely valid, and the test has passed. We were
98+
// successfully able to use the multichain to construct and
99+
// submit a Zcoin transaction!
100+
confs, err := client.Confirmations(context.Background(), txHash)
101+
Expect(err).ToNot(HaveOccurred())
102+
log.Printf(" %v/3 confirmations", confs)
103+
if confs >= 3 {
104+
break
105+
}
106+
time.Sleep(10 * time.Second)
107+
}
108+
109+
// Check that we can load the output and that it is equal.
110+
// Otherwise, something strange is happening with the RPC
111+
// client.
112+
output2, _, err = client.Output(context.Background(), output.Outpoint)
113+
Expect(err).ToNot(HaveOccurred())
114+
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())
115+
})
116+
})
117+
})
118+
})

docker/docker-compose.env

+11-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,14 @@ export DOGECOIN_ADDRESS=mwjUmhAW68zCtgZpW5b1xD5g7MZew6xPV4
3636
# for which the private key is known by a test suite. This allows the test suite
3737
# access to plenty of testing funds.
3838
export ZCASH_PK=cNSVbbsAcBQ6BAmMr6yH6DLWr7QTDptHwdzpy4GYxGDkNZeKnczK
39-
export ZCASH_ADDRESS=tmCTReBSJEDMWfFCkXXPMSB3EfuPg6SE9dw
39+
export ZCASH_ADDRESS=tmCTReBSJEDMWfFCkXXPMSB3EfuPg6SE9dw
40+
41+
#
42+
# Zcoin
43+
#
44+
45+
# Address that will receive mining rewards. Generally, this is set to an address
46+
# for which the private key is known by a test suite. This allows the test suite
47+
# access to plenty of testing funds.
48+
export ZCOIN_PK=cRgCPDGWj9mCKaZ9cd6VkUuVZZakomga4nVkLCH5r3xUXbxKNSci
49+
export ZCOIN_ADDRESS=TTnPecgXLVLQedi2Y7ZrPSh54hnDGHmf1M

docker/docker-compose.yaml

+22-8
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ services:
3030
## Dogecoin
3131
##
3232

33-
dogecoin:
34-
build:
35-
context: ./dogecoin
36-
ports:
37-
- "0.0.0.0:18332:18332"
38-
entrypoint:
39-
- "./root/run.sh"
40-
- "${DOGECOIN_ADDRESS}"
33+
#dogecoin:
34+
# build:
35+
# context: ./dogecoin
36+
# ports:
37+
# - "0.0.0.0:18332:18332"
38+
# entrypoint:
39+
# - "./root/run.sh"
40+
# - "${DOGECOIN_ADDRESS}"
4141
# ##
4242
# ## Zcash
4343
# ##
@@ -49,3 +49,17 @@ services:
4949
# entrypoint:
5050
# - "./root/run.sh"
5151
# - "${ZCASH_ADDRESS}"
52+
53+
# ##
54+
# ## Zcoin
55+
# ##
56+
57+
zcoin:
58+
build:
59+
context: ./zcoin
60+
ports:
61+
- "0.0.0.0:19232:19232"
62+
entrypoint:
63+
- "./root/run.sh"
64+
- "${ZCOIN_ADDRESS}"
65+

docker/zcoin/Dockerfile

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM ubuntu:xenial
2+
3+
RUN apt-get update --fix-missing && apt-get install --yes software-properties-common
4+
5+
# Install all of the dependencies that are needed to build zcoind and
6+
# zcoin-cli from source.
7+
RUN apt-get update && apt-get install -y \
8+
automake \
9+
bsdmainutils \
10+
curl \
11+
g++ \
12+
git \
13+
libboost-all-dev \
14+
libevent-dev \
15+
libssl-dev \
16+
libtool \
17+
libzmq3-dev \
18+
make \
19+
openjdk-8-jdk \
20+
pkg-config \
21+
zlib1g-dev \
22+
libminizip-dev \
23+
cmake \
24+
libgmp-dev
25+
26+
# Install Berkeley DB 4.8
27+
RUN curl -L http://download.oracle.com/berkeley-db/db-4.8.30.tar.gz | tar -xz -C /tmp && \
28+
cd /tmp/db-4.8.30/build_unix && \
29+
../dist/configure --enable-cxx --includedir=/usr/include/bdb4.8 --libdir=/usr/lib && \
30+
make && make install && \
31+
cd / && rm -rf /tmp/db-4.8.30
32+
33+
# Clone the repository and build.
34+
RUN git clone https://github.com/zcoinofficial/zcoin && \
35+
cd zcoin && \
36+
./autogen.sh && \
37+
./configure --without-gui --without-miniupnpc && \
38+
make && \
39+
make install
40+
41+
COPY zcoin.conf /root/.zcoin/zcoin.conf
42+
COPY run.sh /root/run.sh
43+
RUN chmod +x /root/run.sh
44+
45+
# Regtest network port
46+
EXPOSE 19232
47+
48+
ENTRYPOINT ["./root/run.sh"]

docker/zcoin/run.sh

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
ADDRESS=$1
3+
4+
# Start
5+
zcoind -conf=/root/.zcoin/zcoin.conf # -server -rpcbind=0.0.0.0 -rpcallowip=0.0.0.0/0 -rpcuser=user -rpcpassword=password
6+
sleep 10
7+
8+
# Print setup
9+
echo "ZCOIN_ADDRESS=$ADDRESS"
10+
11+
# Import the address
12+
zcoin-cli importaddress $ADDRESS
13+
14+
# Generate enough blocks to pass the maturation time
15+
zcoin-cli generatetoaddress 101 $ADDRESS
16+
17+
# Simulate mining
18+
while :
19+
do
20+
zcoin-cli generatetoaddress 1 $ADDRESS
21+
sleep 10
22+
done

docker/zcoin/zcoin.conf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
daemon=1
2+
regtest=1
3+
rpcuser=user
4+
rpcpassword=password
5+
rpcallowip=0.0.0.0/0
6+
server=1
7+
txindex=1
8+
9+
[regtest]
10+
rpcport=19232

multichain.go

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const (
1313
BTC = Asset("BTC") // Bitcoin
1414
DOGE = Asset("DOGE") // Dogecoin
1515
ETH = Asset("ETH") // Ether
16+
XZC = Asset("XZC") // Zcoin
1617
ZEC = Asset("ZEC") // Zcash
1718
)
1819

@@ -44,6 +45,7 @@ const (
4445
BitcoinCash = Chain("BitcoinCash")
4546
Ethereum = Chain("Ethereum")
4647
Zcash = Chain("Zcash")
48+
Zcoin = Chain("Zcoin")
4749
)
4850

4951
// SizeHint returns the number of bytes required to represent the chain in

0 commit comments

Comments
 (0)