diff --git a/go.mod b/go.mod index 0b489eae..a3ff6bf2 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/renproject/multichain go 1.14 require ( + github.com/bitspill/flod v0.0.0-20200117025253-bf2a74ee75ee + github.com/bitspill/floutil v0.0.0-20180525171018-986e42f96cdb github.com/btcsuite/btcd v0.21.0-beta github.com/btcsuite/btcutil v1.0.2 github.com/codahale/blake2 v0.0.0-20150924215134-8d10d0420cbf diff --git a/go.sum b/go.sum index 83c8ff33..c0ce7638 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,7 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -111,6 +112,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitspill/flod v0.0.0-20200117025253-bf2a74ee75ee h1:476ERazmPwtjvvql0dnhuOzf/kUrLamIroxN4A28fS8= +github.com/bitspill/flod v0.0.0-20200117025253-bf2a74ee75ee/go.mod h1:LetTvR2HhZ+uZu1uLNpgojvBZLlbrl/Hc/PF3fSButU= +github.com/bitspill/floutil v0.0.0-20180525171018-986e42f96cdb h1:lh+MYkoOjrNMjvc3EZZjHDupTt/ZXhDlsowEWkeQ+dY= +github.com/bitspill/floutil v0.0.0-20180525171018-986e42f96cdb/go.mod h1:q+n3qEcw8dizD/RCkEpKMnDsjnNSDP9V8Bq0//zeuoI= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= @@ -206,6 +211,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= diff --git a/infra/.env b/infra/.env index 92ced4f5..2c527ec1 100644 --- a/infra/.env +++ b/infra/.env @@ -58,6 +58,12 @@ export ETHEREUM_ADDRESS=0xa0df350d2637096571F7A701CBc1C5fdE30dF76A export FILECOIN_PK=7b2254797065223a22736563703235366b31222c22507269766174654b6579223a22756d6a634e436a487a5438455757485849754a4c4b58745035437153323435666238626c656c756e5448493d227d export FILECOIN_ADDRESS=f1ej2tountzqwnu6uswhqdzvw6yy5xvcig6rxl2qa +# +# Flo +# +export FLO_PK=cUfPG4c87ZhNjTWmiABHapCvwj4N11KYwLsK9FQCa6oXpWz6MEjv +export FLO_ADDRESS=oYtdP8ahWoetwBrkNz4AZrHu2FTFhhzL83 + # # Terra # diff --git a/infra/docker-compose.yaml b/infra/docker-compose.yaml index b30be3fb..4c4c210b 100644 --- a/infra/docker-compose.yaml +++ b/infra/docker-compose.yaml @@ -112,6 +112,19 @@ services: entrypoint: - "/root/run.sh" + # + # Flo + # + flo: + build: + context: ./flo + ports: + - "0.0.0.0:8333:8333" + entrypoint: + - "./root/run.sh" + - "${FLO_ADDRESS}" + + # # Solana # diff --git a/infra/flo/Dockerfile b/infra/flo/Dockerfile new file mode 100644 index 00000000..877919bd --- /dev/null +++ b/infra/flo/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:xenial + +RUN apt-get update --fix-missing && apt-get install --yes software-properties-common wget + +RUN wget -c https://github.com/floblockchain/flo/releases/download/v0.15.2.1/flo-0.15.2-x86_64-linux-gnu.tar.gz -O - | tar xz +RUN mv ./flo-0.15.2 /app +RUN chmod +x /app/bin/flod +RUN chmod +x /app/bin/flo-cli + +COPY flo.conf /root/.flo/flo.conf +COPY run.sh /root/run.sh +RUN chmod +x /root/run.sh + +EXPOSE 8333 + +ENTRYPOINT ["./root/run.sh"] diff --git a/infra/flo/flo.conf b/infra/flo/flo.conf new file mode 100644 index 00000000..bbbc820b --- /dev/null +++ b/infra/flo/flo.conf @@ -0,0 +1,12 @@ +daemon=1 +regtest=1 +rpcuser=user +rpcpassword=password +rpcallowip=0.0.0.0/0 +rpcport=8333 +server=1 +txindex=1 + +[regtest] +rpcbind=0.0.0.0 + diff --git a/infra/flo/keygen.go b/infra/flo/keygen.go new file mode 100644 index 00000000..39b19a6b --- /dev/null +++ b/infra/flo/keygen.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "github.com/bitspill/flod/floec" + "github.com/bitspill/floutil" + + "github.com/renproject/id" + "github.com/renproject/multichain/chain/flo" +) + +func main() { + privKey := id.NewPrivKey() + wif, err := floutil.NewWIF((*floec.PrivateKey)(privKey), &flo.RegressionNetParams, true) + if err != nil { + panic(err) + } + addrPubKeyHash, err := floutil.NewAddressPubKeyHash(floutil.Hash160(wif.SerializePubKey()), &flo.RegressionNetParams) + if err != nil { + panic(err) + } + fmt.Printf("FLO_PK=%v\n", wif) + fmt.Printf("FLO_ADDRESS=%v\n", addrPubKeyHash) +} diff --git a/infra/flo/run.sh b/infra/flo/run.sh new file mode 100644 index 00000000..3233fadd --- /dev/null +++ b/infra/flo/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash +ADDRESS=$1 + +# Start +/app/bin/flod -conf=/root/.flo/flo.conf # -server -rpcbind=0.0.0.0 -rpcallowip=0.0.0.0/0 -rpcuser=user -rpcpassword=password +sleep 10 + + +# Print setup +echo "FLO_ADDRESS=$ADDRESS" + +# Import the address +/app/bin/flo-cli importaddress $ADDRESS + +echo "done" + +# Generate enough block to pass the maturation time +/app/bin/flo-cli generatetoaddress 101 $ADDRESS + +# Simulate mining +while : +do + /app/bin/flo-cli generatetoaddress 1 $ADDRESS + sleep 10 +done \ No newline at end of file diff --git a/multichain.go b/multichain.go index 436a7fc0..c89d21c3 100644 --- a/multichain.go +++ b/multichain.go @@ -107,6 +107,7 @@ const ( DOGE = Asset("DOGE") // Dogecoin ETH = Asset("ETH") // Ether FIL = Asset("FIL") // Filecoin + FLO = Asset("FLO") // Flo FTM = Asset("FTM") // Fantom SOL = Asset("SOL") // Solana LUNA = Asset("LUNA") // Luna @@ -140,6 +141,8 @@ func (asset Asset) OriginChain() Chain { return Ethereum case FIL: return Filecoin + case FLO: + return Flo case FTM: return Fantom case LUNA: @@ -167,7 +170,7 @@ func (asset Asset) OriginChain() Chain { // ChainType returns the chain-type (Account or UTXO) for the given asset func (asset Asset) ChainType() ChainType { switch asset { - case BCH, BTC, DGB, DOGE, ZEC: + case BCH, BTC, DGB, DOGE, FLO, ZEC: return ChainTypeUTXOBased case BNB, ETH, FIL, LUNA: return ChainTypeAccountBased @@ -218,6 +221,7 @@ const ( Ethereum = Chain("Ethereum") Fantom = Chain("Fantom") Filecoin = Chain("Filecoin") + Flo = Chain("Flo") Solana = Chain("Solana") Terra = Chain("Terra") Zcash = Chain("Zcash") @@ -252,7 +256,7 @@ func (chain *Chain) Unmarshal(buf []byte, rem int) ([]byte, int, error) { // for the chain. func (chain Chain) ChainType() ChainType { switch chain { - case Bitcoin, BitcoinCash, DigiByte, Dogecoin, Zcash: + case Bitcoin, BitcoinCash, DigiByte, Dogecoin, Flo, Zcash: return ChainTypeUTXOBased case BinanceSmartChain, Ethereum, Filecoin, Terra: return ChainTypeAccountBased @@ -300,6 +304,8 @@ func (chain Chain) NativeAsset() Asset { return ETH case Filecoin: return FIL + case Flo: + return FLO case Terra: return LUNA case Zcash: diff --git a/multichain_test.go b/multichain_test.go index 27f5165e..64115ff5 100644 --- a/multichain_test.go +++ b/multichain_test.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/bitspill/flod/floec" "math/rand" "os" "os/exec" @@ -14,6 +15,8 @@ import ( "testing/quick" "time" + flochaincfg "github.com/bitspill/flod/chaincfg" + "github.com/bitspill/floutil" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" @@ -30,6 +33,7 @@ import ( // "github.com/renproject/multichain/chain/digibyte" "github.com/renproject/multichain/chain/dogecoin" "github.com/renproject/multichain/chain/filecoin" + "github.com/renproject/multichain/chain/flo" "github.com/renproject/multichain/chain/terra" "github.com/renproject/multichain/chain/zcash" "github.com/renproject/pack" @@ -147,6 +151,61 @@ var _ = Describe("Multichain", func() { return multichain.RawAddress([]byte{}) }, }, + { + multichain.Flo, + func() multichain.AddressEncodeDecoder { + addrEncodeDecoder := flo.NewAddressEncodeDecoder(&flochaincfg.RegressionNetParams) + return addrEncodeDecoder + }, + func() multichain.Address { + // Generate a random SECP256K1 private key. + pk := id.NewPrivKey() + // Get flo WIF private key with the pub key configured to be in + // the compressed form. + wif, err := floutil.NewWIF((*floec.PrivateKey)(pk), &flochaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := floutil.NewAddressPubKeyHash(floutil.Hash160(wif.SerializePubKey()), &flochaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Return the human-readable encoded flo address in base58 format. + return multichain.Address(addrPubKeyHash.EncodeAddress()) + }, + func() multichain.RawAddress { + // Generate a random SECP256K1 private key. + pk := id.NewPrivKey() + // Get flo WIF private key with the pub key configured to be in + // the compressed form. + wif, err := floutil.NewWIF((*floec.PrivateKey)(pk), &flochaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + // Get the address pubKey hash. This is the most commonly used format + // for a flo address. + addrPubKeyHash, err := floutil.NewAddressPubKeyHash(floutil.Hash160(wif.SerializePubKey()), &flochaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Encode into the checksummed base58 format. + encoded := addrPubKeyHash.EncodeAddress() + return multichain.RawAddress(pack.Bytes(base58.Decode(encoded))) + }, + func() multichain.Address { + // Random bytes of script. + script := make([]byte, r.Intn(100)) + r.Read(script) + // Create address script hash from the random script bytes. + addrScriptHash, err := floutil.NewAddressScriptHash(script, &flochaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Return in human-readable encoded form. + return multichain.Address(addrScriptHash.EncodeAddress()) + }, + func() multichain.RawAddress { + // Random bytes of script. + script := make([]byte, r.Intn(100)) + r.Read(script) + // Create address script hash from the random script bytes. + addrScriptHash, err := floutil.NewAddressScriptHash(script, &flochaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Encode to the checksummed base58 format. + encoded := addrScriptHash.EncodeAddress() + return multichain.RawAddress(pack.Bytes(base58.Decode(encoded))) + }, + }, { multichain.Terra, func() multichain.AddressEncodeDecoder {