Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions chain/bitgesell/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package bitgesell

import "github.com/renproject/multichain/chain/bitcoin"

type (
// AddressEncoder re-exports bitcoin.AddressEncoder.
AddressEncoder = bitcoin.AddressEncoder

// AddressDecoder re-exports bitcoin.AddressDecoder.
AddressDecoder = bitcoin.AddressDecoder

// AddressEncodeDecoder re-exports bitcoin.AddressEncodeDecoder.
AddressEncodeDecoder = bitcoin.AddressEncodeDecoder
)
1 change: 1 addition & 0 deletions chain/bitgesell/address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package bitgesell_test
82 changes: 82 additions & 0 deletions chain/bitgesell/bitgesell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package bitgesell

import (
"github.com/bitgesellofficial/bgld/chaincfg"
"github.com/renproject/multichain/chain/bitcoin"
)

func init() {
if err := chaincfg.Register(&MainNetParams); err != nil {
panic(err)
}
if err := chaincfg.Register(&TestNetParams); err != nil {
panic(err)
}
if err := chaincfg.Register(&RegressionNetParams); err != nil {
panic(err)
}
}

// MainNetParams returns the chain configuration for mainnet.
var MainNetParams = chaincfg.Params{
Name: "mainnet",
Net: 0x8ab491e8,

// Address encoding magics
PubKeyHashAddrID: 10,
ScriptHashAddrID: 25,
PrivateKeyID: 128,

// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x02, 0xfa, 0xc3, 0x98}, // starts with xprv
HDPublicKeyID: [4]byte{0x02, 0xfa, 0xca, 0xfd}, // starts with xpub

// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "bgl",
}

// TestNetParams returns the chain configuration for testnet.
var TestNetParams = chaincfg.Params{
Name: "testnet",
Net: 0xc2b5d9e6,

// Address encoding magics
PubKeyHashAddrID: 34,
ScriptHashAddrID: 50,
PrivateKeyID: 239,

// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with xprv
HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with xpub

// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "tbgl",
}

// RegressionNetParams returns the chain configuration for regression net.
var RegressionNetParams = chaincfg.Params{
Name: "regtest",
Net: 0xd98cbfba,

// Address encoding magics
PubKeyHashAddrID: 34,
ScriptHashAddrID: 50,
PrivateKeyID: 239,

// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with xprv
HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with xpub

// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "rbgl",
}

// DefaultClientOptions returns ClientOptions with the default settings. These
// settings are valid for use with the default local deployment of the
// multichain. In production, the host, user, and password should be changed.
func DefaultClientOptions() ClientOptions {
return bitcoin.DefaultClientOptions().WithHost("http://0.0.0.0:18475")
}
13 changes: 13 additions & 0 deletions chain/bitgesell/bitgesell_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package bitgesell_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestBitgesell(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Bitgesell Suite")
}
138 changes: 138 additions & 0 deletions chain/bitgesell/bitgesell_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package bitgesell_test

import (
"context"
"log"
"os"
"reflect"
"time"

"github.com/bitgesellofficial/bgld/chaincfg"
"github.com/bitgesellofficial/bglutil"
"github.com/renproject/id"
"github.com/renproject/multichain/api/address"
"github.com/renproject/multichain/api/utxo"
"github.com/renproject/multichain/chain/bitgesell"
"github.com/renproject/pack"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Bitgesell", func() {
Context("when submitting transactions", func() {
Context("when sending BGL to multiple addresses", func() {
It("should work", func() {
// Load private key, and assume that the associated address has
// funds to spend. You can do this by setting BGL_PK to the
// value specified in the `./multichaindeploy/.env` file.
pkEnv := os.Getenv("BGL_PK")
if pkEnv == "" {
panic("BGL_PK is undefined")
}
wif, err := bglutil.DecodeWIF(pkEnv)
Expect(err).ToNot(HaveOccurred())

// note: legacy (non-witness) addresses are not supported in Bitgesell
// WPKH
wpkAddr, err := bglutil.NewAddressWitnessPubKeyHash([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}, &bitgesell.RegressionNetParams)
Expect(err).ToNot(HaveOccurred())
log.Printf("WPKH %v", wpkAddr.EncodeAddress())

// Setup the client and load the unspent transaction outputs.
client := bitgesell.NewClient(bitgesell.DefaultClientOptions())
outputs, err := client.UnspentOutputs(context.Background(), 0, 999999999, address.Address(os.Getenv("BGL_ADDRESS")))
Expect(err).ToNot(HaveOccurred())
Expect(len(outputs)).To(BeNumerically(">", 0))
output := outputs[0]

// Check that we can load the output and that it is equal.
// Otherwise, something strange is happening with the RPC
// client.
output2, _, err := client.Output(context.Background(), output.Outpoint)
Expect(err).ToNot(HaveOccurred())
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())
output2, _, err = client.UnspentOutput(context.Background(), output.Outpoint)
Expect(err).ToNot(HaveOccurred())
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())

// Build the transaction by consuming the outputs and spending
// them to a set of recipients.
inputs := []utxo.Input{
{Output: utxo.Output{
Outpoint: utxo.Outpoint{
Hash: output.Outpoint.Hash[:],
Index: output.Outpoint.Index,
},
PubKeyScript: output.PubKeyScript,
Value: output.Value,
}},
}
recipients := []utxo.Recipient{
{
To: address.Address(os.Getenv("BGL_ADDRESS")),
Value: pack.NewU256FromU64(pack.NewU64((output.Value.Int().Uint64() - 1000) / 2)),
},
{
To: address.Address(wpkAddr.EncodeAddress()),
Value: pack.NewU256FromU64(pack.NewU64((output.Value.Int().Uint64() - 1000) / 2)),
},
}
tx, err := bitgesell.NewTxBuilder(&chaincfg.RegressionNetParams).BuildTx(inputs, recipients)
Expect(err).ToNot(HaveOccurred())

// Get the digests that need signing from the transaction, and
// sign them. In production, this would be done using the RZL
// MPC algorithm, but for the purposes of this test, using an
// explicit privkey is ok.
sighashes, err := tx.Sighashes()

signatures := make([]pack.Bytes65, len(sighashes))
Expect(err).ToNot(HaveOccurred())
for i := range sighashes {
hash := id.Hash(sighashes[i])
privKey := (*id.PrivKey)(wif.PrivKey)
signature, err := privKey.Sign(&hash)
Expect(err).ToNot(HaveOccurred())
signatures[i] = pack.NewBytes65(signature)
}
Expect(tx.Sign(signatures, pack.NewBytes(wif.SerializePubKey()))).To(Succeed())

// Submit the transaction to the Bitgesell node. Again, this
// should be running a la `./multichaindeploy`.
txHash, err := tx.Hash()
Expect(err).ToNot(HaveOccurred())
err = client.SubmitTx(context.Background(), tx)
Expect(err).ToNot(HaveOccurred())
log.Printf("TXID %v", txHash)

for {
// Loop until the transaction has at least a few
// confirmations. This implies that the transaction is
// definitely valid, and the test has passed. We were
// successfully able to use the multichain to construct and
// submit a Bitgesell transaction!
log.Printf("Checking for confirmations...")
confs, err := client.Confirmations(context.Background(), txHash)
Expect(err).ToNot(HaveOccurred())
log.Printf(" %v/3 confirmations", confs)
if confs >= 1 {
break
}
time.Sleep(10 * time.Second)
}
ctxWithTimeout, cancelCtxWithTimeout := context.WithTimeout(context.Background(), time.Second)
defer cancelCtxWithTimeout()
_, _, err = client.UnspentOutput(ctxWithTimeout, output.Outpoint)
Expect(err).To(HaveOccurred())

// Check that we can load the output and that it is equal.
// Otherwise, something strange is happening with the RPC
// client.
output2, _, err = client.Output(context.Background(), output.Outpoint)
Expect(err).ToNot(HaveOccurred())
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())
})
})
})
})
9 changes: 9 additions & 0 deletions chain/bitgesell/gas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package bitgesell

import "github.com/renproject/multichain/chain/bitcoin"

// GasEstimator re-exports bitcoin.GasEstimator.
type GasEstimator = bitcoin.GasEstimator

// NewGasEstimator re-exports bitcoin.NewGasEstimator.
var NewGasEstimator = bitcoin.NewGasEstimator
52 changes: 52 additions & 0 deletions chain/bitgesell/gas_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package bitgesell_test

import (
"context"

"github.com/renproject/multichain/chain/bitgesell"
"github.com/renproject/pack"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Gas", func() {
Context("when estimating Bitgesell network fee", func() {
It("should work", func() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := bitgesell.NewClient(bitgesell.DefaultClientOptions())

// estimate fee to include tx within 1 block.
fallback1 := uint64(123)
gasEstimator1 := bitgesell.NewGasEstimator(client, 1, pack.NewU256FromUint64(fallback1))
gasPrice1, _, err := gasEstimator1.EstimateGas(ctx)
if err != nil {
Expect(gasPrice1).To(Equal(pack.NewU256FromUint64(fallback1)))
}

// estimate fee to include tx within 10 blocks.
fallback2 := uint64(234)
gasEstimator2 := bitgesell.NewGasEstimator(client, 10, pack.NewU256FromUint64(fallback2))
gasPrice2, _, err := gasEstimator2.EstimateGas(ctx)
if err != nil {
Expect(gasPrice2).To(Equal(pack.NewU256FromUint64(fallback2)))
}

// estimate fee to include tx within 100 blocks.
fallback3 := uint64(345)
gasEstimator3 := bitgesell.NewGasEstimator(client, 100, pack.NewU256FromUint64(fallback3))
gasPrice3, _, err := gasEstimator3.EstimateGas(ctx)
if err != nil {
Expect(gasPrice3).To(Equal(pack.NewU256FromUint64(fallback3)))
}

// expect fees in this order at the very least.
if err == nil {
Expect(gasPrice1.GreaterThanEqual(gasPrice2)).To(BeTrue())
Expect(gasPrice2.GreaterThanEqual(gasPrice3)).To(BeTrue())
}
})
})
})
Loading