├── .gitignore ├── .gitmodules ├── BSDmakefile ├── LICENSE ├── Makefile ├── README.md ├── account ├── account.go ├── account_test.go ├── bip39.go ├── doc.go ├── phrase.go ├── phrase_test.go ├── private.go ├── private_test.go ├── seed.go ├── seed_test.go └── signature.go ├── announce ├── announce.go ├── announce_test.go ├── announcer.go ├── announcer_test.go ├── broadcast │ ├── broadcast.go │ └── broadcast_test.go ├── doc.go ├── domain │ ├── domain.go │ ├── domain_test.go │ ├── lookuper.go │ ├── txt.go │ └── txt_test.go ├── fingerprint │ ├── fingerprint.go │ └── fingerprint_test.go ├── fixtures │ └── fixtures.go ├── helper │ ├── helper.go │ └── helper_test.go ├── id │ ├── id.go │ └── id_test.go ├── mocks │ ├── mock_receptor.go │ ├── mock_rpc.go │ └── mock_zmqclient.go ├── parameter │ └── parameter.go ├── receptor │ ├── data.go │ ├── data_test.go │ ├── receptor.go │ └── receptor_test.go ├── rpc.go ├── rpc │ ├── rpc.go │ └── rpc_test.go └── setup.go ├── asset ├── asset.go ├── asset_test.go ├── doc.go └── expiry.go ├── avl ├── allocator.go ├── avl_test.go ├── check.go ├── delete.go ├── doc.go ├── get.go ├── insert.go ├── iterator.go ├── print.go ├── search.go └── setup.go ├── background ├── background.go ├── background_test.go ├── doc.go └── example_test.go ├── block ├── block_test.go ├── blockstore.go ├── delete.go ├── doc.go ├── recovery.go ├── setup.go └── store.go ├── blockdigest ├── digest.go ├── digest_test.go └── doc.go ├── blockdump ├── doc.go └── dump.go ├── blockheader ├── common_test.go ├── doc.go ├── get.go ├── header_test.go └── setup.go ├── blockrecord ├── doc.go ├── header.go ├── nonce.go ├── nonce_test.go ├── records_test.go ├── validator.go └── validator_test.go ├── chain ├── chain_test.go ├── chains.go └── doc.go ├── command ├── bitmark-cli │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── agent.go │ ├── bin │ │ └── ask-gpg-agent │ ├── check_commands.go │ ├── configuration │ │ ├── configuration_test.go │ │ ├── doc.go │ │ ├── encrypt.go │ │ ├── encrypt_test.go │ │ ├── salt.go │ │ ├── salt_test.go │ │ ├── setup.go │ │ └── write.go │ ├── doc.go │ ├── main.go │ ├── main_test.go │ ├── password.go │ ├── printjson.go │ ├── rpccalls │ │ ├── asset.go │ │ ├── balance.go │ │ ├── blockdecode.go │ │ ├── blockdump.go │ │ ├── blocktransfer.go │ │ ├── countersign.go │ │ ├── doc.go │ │ ├── fullprovenance.go │ │ ├── grant.go │ │ ├── info.go │ │ ├── issue.go │ │ ├── owned.go │ │ ├── payment-command.go │ │ ├── printjson.go │ │ ├── provenance.go │ │ ├── rpccalls_test.go │ │ ├── setup.go │ │ ├── share.go │ │ ├── status.go │ │ ├── swap.go │ │ └── transfer.go │ ├── run-add.go │ ├── run-balance.go │ ├── run-bitmarkdinfo.go │ ├── run-blockdecode.go │ ├── run-blockdump.go │ ├── run-blocktransfer.go │ ├── run-changepassword.go │ ├── run-countersign.go │ ├── run-create.go │ ├── run-fingerprint.go │ ├── run-fullprovenance.go │ ├── run-grant.go │ ├── run-list.go │ ├── run-owned.go │ ├── run-provenance.go │ ├── run-seed.go │ ├── run-setup.go │ ├── run-share.go │ ├── run-sign.go │ ├── run-swap.go │ ├── run-transactionstatus.go │ └── run-transfer.go ├── bitmark-dumpdb │ ├── doc.go │ ├── main.go │ └── main_test.go ├── bitmark-info │ ├── README.md │ ├── doc.go │ ├── main.go │ └── main_test.go ├── bitmarkd │ ├── binary-block.go │ ├── bitmarkd.conf.sample │ ├── bitmarkd.conf.sub │ ├── certificates.go │ ├── commands.go │ ├── configuration.go │ ├── doc.go │ ├── main.go │ ├── main_test.go │ └── stats.go ├── bm-rate │ ├── doc.go │ ├── main.go │ └── main_test.go ├── dbdelete │ └── main.go ├── dbmatch │ └── main.go ├── makegenesis │ ├── common_test.go │ ├── gt_test.go │ └── main.go ├── makeproof │ └── main.go ├── recorderd │ ├── commands.go │ ├── config_reader.go │ ├── config_reader_test.go │ ├── configuration.go │ ├── doc.go │ ├── file_watcher.go │ ├── file_watcher_test.go │ ├── job_calendar.go │ ├── job_calendar_test.go │ ├── job_manager.go │ ├── job_manager_test.go │ ├── main.go │ ├── main_test.go │ ├── proofer.go │ ├── proofer_test.go │ ├── recorderd.conf.sample │ ├── submitter.go │ └── subscriber.go ├── recoverbadkey │ └── main.go └── simbm │ ├── .gitignore │ ├── commands.go │ ├── configuration.go │ ├── doc.go │ ├── main.go │ ├── publisher.go │ ├── simbm.conf.sample │ └── submission.go ├── configuration ├── configuration_test.go ├── doc.go └── luareader.go ├── constants ├── constants.go ├── constants_test.go └── doc.go ├── counter ├── counter.go ├── counter_test.go └── doc.go ├── currency ├── bitcoin │ ├── doc.go │ ├── validate.go │ └── validate_test.go ├── chain.go ├── chain_test.go ├── conversion.go ├── currency_test.go ├── doc.go ├── enumerated.go ├── fees.go ├── litecoin │ ├── doc.go │ ├── frombitcoin.go │ ├── frombitcoin_test.go │ ├── validate.go │ └── validate_test.go ├── mapped.go ├── mapped_test.go ├── marshalling.go ├── satoshi │ ├── doc.go │ ├── satoshi.go │ └── satoshi_test.go ├── set.go └── validate.go ├── debian ├── .gitignore ├── README.debian ├── bitmark-cli.install ├── bitmark-info.install ├── bitmarkd.install ├── bitmarkd.postinst ├── bitmarkd.postrm ├── bitmarkd.preinst ├── bitmarkd.prerm ├── bitmarkd.service ├── changelog ├── compat ├── control ├── copyright ├── dumpdb.install ├── recorderd.install ├── recorderd.postinst ├── recorderd.postrm ├── recorderd.preinst ├── recorderd.prerm ├── recorderd.service ├── rules └── source │ └── format ├── difficulty ├── difficulty.go ├── difficulty_test.go └── doc.go ├── doc ├── payment.md └── release-note-template.md ├── fault ├── doc.go ├── fault.go ├── fault_test.go └── generate-fault.sh ├── genesis ├── doc.go ├── genesis.go └── genesis_test.go ├── go.mod ├── go.sum ├── hooks ├── pre-commit └── pre-push ├── merkle ├── digest.go ├── digest_test.go ├── doc.go ├── merkle.go └── merkle_test.go ├── messagebus ├── doc.go ├── queue.go └── queue_test.go ├── mode ├── doc.go ├── mode.go └── mode_test.go ├── ownership ├── data.go ├── data_test.go ├── doc.go ├── item.go ├── list.go ├── ownership.go └── transfer.go ├── pay ├── doc.go ├── payid.go └── payid_test.go ├── payment ├── background.go ├── bitcoin.go ├── common_test.go ├── currencyhandler.go ├── doc.go ├── litecoin.go ├── p2p.go ├── p2p_test.go ├── payment_test.go ├── peermap.go ├── peermap_test.go └── setup.go ├── peer ├── connector.go ├── connector_state.go ├── connector_test.go ├── doc.go ├── listener.go ├── mocks │ ├── generate.sh │ ├── mock_upstream.go │ └── mock_zmqutil_client.go ├── peer_test.go ├── process.go ├── rpcs.go ├── setup.go ├── upstream │ ├── doc.go │ ├── setup.go │ ├── upstream.go │ └── upstream_test.go └── voting │ ├── voting.go │ └── voting_test.go ├── proof ├── doc.go ├── internal_hasher.go ├── internal_hasher_test.go ├── proof_test.go ├── publisher.go ├── queue.go ├── setup.go └── submission.go ├── publish ├── broadcaster.go ├── doc.go ├── publish_test.go └── setup.go ├── release-notes.md ├── reservoir ├── broadcast.go ├── common_test.go ├── difficulty.go ├── doc.go ├── expiration.go ├── fetch.go ├── issues.go ├── loadsave.go ├── loadsave_test.go ├── mocks │ └── mock_handle.go ├── payment.go ├── paynonce.go ├── paynonce_test.go ├── restorer.go ├── setup.go ├── sharebalance.go ├── sharegrant.go ├── shareswap.go ├── trackingstatus.go └── transfer.go ├── rpc ├── assets │ ├── assets.go │ └── assets_test.go ├── bitmark │ ├── bitmark.go │ └── bitmark_test.go ├── bitmarks │ ├── bitmarks.go │ └── bitmarks_test.go ├── blockowner │ ├── blockowner.go │ └── blockowner_test.go ├── certificate │ ├── certificate.go │ └── certificate_test.go ├── doc.go ├── fixtures │ ├── fixtures.go │ ├── test.crt │ └── test.key ├── handler │ ├── handler.go │ └── handler_test.go ├── listeners │ ├── https.go │ ├── https_test.go │ ├── listeners.go │ ├── rpc.go │ └── rpc_test.go ├── mocks │ ├── mock_announce.go │ ├── mock_handle.go │ ├── mock_ownership.go │ ├── mock_record.go │ └── mock_reservoir.go ├── node │ ├── node.go │ └── node_test.go ├── owner │ ├── owner.go │ └── owner_test.go ├── ratelimit │ ├── limit.go │ └── limit_test.go ├── rpc_test.go ├── server │ ├── server.go │ └── server_test.go ├── setup.go ├── share │ ├── share.go │ └── share_test.go └── transaction │ ├── transaction.go │ └── transaction_test.go ├── scripts ├── add-license ├── bitmark-repo ├── list-dependencies ├── list-rpcs ├── need-fixes └── setup-hooks.sh ├── sonar-project.properties ├── storage ├── access.go ├── access_test.go ├── cache.go ├── cache_test.go ├── common_test.go ├── cursor.go ├── doc.go ├── handle.go ├── mocks │ ├── mock_access.go │ ├── mock_cache.go │ └── mock_handle.go ├── payment.go ├── payment_test.go ├── pool_test.go ├── setup.go ├── split.go ├── storage_test.go ├── transaction.go └── transaction_test.go ├── testing ├── README.markdown ├── animate-nodes ├── bm-tester ├── create-bitmark-wallet.sh ├── create-node-users.sh ├── genbtcltc ├── generate-bitmarkd-configuration ├── graph-nodes ├── initial-setup.sh ├── make-blockchain ├── node-info ├── restart-all-bitmarkds ├── run-bitcoin ├── run-bitmarkd ├── run-litecoin ├── run-recorderd ├── samples │ ├── bitcoin.conf │ ├── litecoin.conf │ └── recorderd.conf └── show-bitmarkd-info ├── transactionrecord ├── asset_test.go ├── assetidentifier.go ├── assetidentifier_test.go ├── balance_test.go ├── base_test.go ├── blockfoundation_test.go ├── blockownertransfer_test.go ├── common_test.go ├── countersigned_test.go ├── doc.go ├── grant_test.go ├── issue_test.go ├── pack.go ├── swap_test.go ├── transaction.go ├── transfer_test.go ├── transfers.go └── unpack.go ├── util ├── base58.go ├── base58_test.go ├── canonical.go ├── canonical_test.go ├── doc.go ├── fetcher.go ├── formatbytes.go ├── paths.go ├── varint.go └── varint_test.go └── zmqutil ├── authentication.go ├── client.go ├── doc.go ├── keypair.go ├── monitor.go ├── socket.go └── zmqutil_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | bin/ 7 | 8 | # local files 9 | local-*/ 10 | vendor/ 11 | port-tuple.mk 12 | 13 | # Test binary, build with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 20 | .glide/ 21 | 22 | # EDITOR 23 | *.swp 24 | TAGS 25 | tags 26 | .vscode/ 27 | 28 | # LOG 29 | *.log 30 | 31 | # OSX 32 | .DS_Store 33 | -------------------------------------------------------------------------------- /BSDmakefile: -------------------------------------------------------------------------------- 1 | # BSDmakefile 2 | # forward flags, vars, and targets to gmake 3 | 4 | .export 5 | 6 | .if "${.TARGETS}" == "" 7 | 8 | .PHONY: all 9 | all: 10 | gmake ${MAKEFLAGS} 11 | 12 | .else 13 | 14 | .PHONY: ${.TARGETS} 15 | ${.TARGETS}: _internal_ 16 | 17 | .PHONY: _internal_ 18 | _internal_: 19 | gmake ${MAKEFLAGS} ${.TARGETS} 20 | 21 | .endif 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2020 Bitmark Inc. 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /account/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package account - types and functions for converting Bitmark 7 | // accounts (the public key) and their signatures 8 | package account 9 | -------------------------------------------------------------------------------- /account/phrase.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package account 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/fault" 10 | ) 11 | 12 | const ( 13 | phraseV1Length = 24 14 | phraseV2Length = 12 15 | ) 16 | 17 | var masks = []int{0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023} 18 | 19 | // Base58EncodedSeedToPhrase - convert base58 seed to recovery phrase 20 | func Base58EncodedSeedToPhrase(encodedSeed string) ([]string, error) { 21 | 22 | sk, testnet, err := parseBase58Seed(encodedSeed) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | var phraseLength int 28 | 29 | switch len(sk) { 30 | case secretKeyV1Length: 31 | phraseLength = phraseV1Length 32 | 33 | // append network byte to sk 34 | if testnet { 35 | sk = append([]byte{0x01}, sk...) 36 | } else { 37 | sk = append([]byte{0x00}, sk...) 38 | } 39 | 40 | case secretKeyV2Length: 41 | phraseLength = phraseV2Length 42 | 43 | default: 44 | return nil, fault.InvalidSecretKeyLength 45 | } 46 | 47 | phrase := make([]string, 0, phraseLength) 48 | accumulator := 0 49 | bits := 0 50 | n := 0 51 | 52 | for i := 0; i < len(sk); i++ { 53 | accumulator = accumulator<<8 + int(sk[i]) 54 | bits += 8 55 | if bits >= 11 { 56 | bits -= 11 57 | n++ 58 | index := accumulator >> uint(bits) 59 | accumulator &= masks[bits] 60 | word := bip39[index] 61 | phrase = append(phrase, word) 62 | } 63 | } 64 | 65 | if phraseLength != len(phrase) { 66 | return nil, fault.InvalidRecoveryPhraseLength 67 | } 68 | 69 | return phrase, nil 70 | } 71 | -------------------------------------------------------------------------------- /account/phrase_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package account_test 7 | 8 | import ( 9 | "reflect" 10 | "strings" 11 | "testing" 12 | 13 | "github.com/bitmark-inc/bitmarkd/account" 14 | ) 15 | 16 | type item struct { 17 | base58Seed string 18 | phrase string 19 | } 20 | 21 | var validItems = []item{ 22 | { 23 | base58Seed: "9J879ykQwWijwsrQbGop819AiLqk1Jf1Z", 24 | phrase: "hundred diary business foot issue forward penalty broccoli clerk category ship help", 25 | }, 26 | { 27 | base58Seed: "9J878SbnM2GFqAELkkiZbqHJDkAj57fYK", 28 | phrase: "file earn crack fever crack differ wreck crazy salon imitate swamp sample", 29 | }, 30 | { 31 | base58Seed: "5XEECt18HGBGNET1PpxLhy5CsCLG9jnmM6Q8QGF4U2yGb1DABXZsVeD", 32 | phrase: "accident syrup inquiry you clutch liquid fame upset joke glow best school repeat birth library combine access camera organ trial crazy jeans lizard science", 33 | }, 34 | { 35 | base58Seed: "5XEECqxPZwQCBMACLXjT2ZLSkhrFqibTZSb1p1PAwSgqmEwaw46iRpt", 36 | phrase: "about hurt rebel loan pattern water nose affair outside blouse color discover obey jealous portion penalty embrace fog move tool betray weird brother vanish", 37 | }, 38 | } 39 | 40 | func TestValidBase58EncodedSeedToPhrase(t *testing.T) { 41 | for _, item := range validItems { 42 | phrase, err := account.Base58EncodedSeedToPhrase(item.base58Seed) 43 | if err != nil { 44 | t.Errorf("actual error: %s, expected no error", err) 45 | } 46 | 47 | actualPhrase := strings.Join(phrase, " ") 48 | if !reflect.DeepEqual(item.phrase, actualPhrase) { 49 | t.Errorf("actual phrase: %v, expected: %v", actualPhrase, item.phrase) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /account/signature.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package account 7 | 8 | import ( 9 | "encoding/hex" 10 | "fmt" 11 | ) 12 | 13 | // Signature - the type for a signature 14 | type Signature []byte 15 | 16 | // String - convert a binary signature to hex string for use by the fmt package (for %s) 17 | func (signature Signature) String() string { 18 | return hex.EncodeToString(signature) 19 | } 20 | 21 | // GoString - convert a binary signature to hex string for use by the fmt package (for %#v) 22 | func (signature Signature) GoString() string { 23 | return "" 24 | } 25 | 26 | // Scan - convert a text representation to a signature for use by the format package scan routines 27 | func (signature *Signature) Scan(state fmt.ScanState, verb rune) error { 28 | token, err := state.Token(true, func(c rune) bool { 29 | if c >= '0' && c <= '9' { 30 | return true 31 | } 32 | if c >= 'A' && c <= 'F' { 33 | return true 34 | } 35 | if c >= 'a' && c <= 'f' { 36 | return true 37 | } 38 | return false 39 | }) 40 | if err != nil { 41 | return err 42 | } 43 | sig := make([]byte, hex.DecodedLen(len(token))) 44 | byteCount, err := hex.Decode(sig, token) 45 | if err != nil { 46 | return err 47 | } 48 | *signature = sig[:byteCount] 49 | return nil 50 | } 51 | 52 | // MarshalText - convert signature to text 53 | func (signature Signature) MarshalText() ([]byte, error) { 54 | size := hex.EncodedLen(len(signature)) 55 | b := make([]byte, size) 56 | hex.Encode(b, signature) 57 | return b, nil 58 | } 59 | 60 | // UnmarshalText - convert text into a signature 61 | func (signature *Signature) UnmarshalText(s []byte) error { 62 | sig := make([]byte, hex.DecodedLen(len(s))) 63 | byteCount, err := hex.Decode(sig, s) 64 | if err != nil { 65 | return err 66 | } 67 | *signature = sig[:byteCount] 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /announce/announce.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package announce 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/announce/fingerprint" 10 | "github.com/bitmark-inc/bitmarkd/announce/rpc" 11 | ) 12 | 13 | type Announce interface { 14 | // Set - set this node's rpc announcement data 15 | Set(fingerprint.Fingerprint, []byte) error 16 | 17 | // Fetch- fetch some records 18 | Fetch(uint64, int) ([]rpc.Entry, uint64, error) 19 | } 20 | 21 | // Get - return Announce interface 22 | func Get() Announce { 23 | return globalData.rpcs 24 | } 25 | -------------------------------------------------------------------------------- /announce/announcer.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package announce 7 | 8 | import ( 9 | "encoding/binary" 10 | "time" 11 | 12 | "github.com/bitmark-inc/bitmarkd/mode" 13 | "github.com/bitmark-inc/bitmarkd/zmqutil" 14 | ) 15 | 16 | // SendRegistration - send a peer registration request to a client channel 17 | func SendRegistration(client zmqutil.Client, fn string) error { 18 | chain := mode.ChainName() 19 | 20 | // get a big endian timestamp 21 | timestamp := make([]byte, 8) 22 | binary.BigEndian.PutUint64(timestamp, uint64(time.Now().Unix())) 23 | 24 | return client.Send(fn, chain, []byte(globalData.receptors.ID()), globalData.receptors.SelfListener(), timestamp) 25 | } 26 | 27 | // AddPeer - add a peer announcement to the in-memory tree 28 | // returns: 29 | // 30 | // true if this was a new/updated entry 31 | // false if the update was within the limits (to prevent continuous relaying) 32 | func AddPeer(publicKey []byte, listeners []byte, timestamp uint64) bool { 33 | return globalData.receptors.Add(publicKey, listeners, timestamp) 34 | } 35 | 36 | // GetRandom - fetch the data for a random node in the ring not matching a given public key 37 | func GetRandom(publicKey []byte) ([]byte, []byte, time.Time, error) { 38 | return globalData.receptors.Random(publicKey) 39 | } 40 | 41 | // SetPeer - called by the peering initialisation to set up this 42 | // node's announcement data 43 | func SetSelf(publicKey []byte, listeners []byte) error { 44 | return globalData.receptors.SetSelf(publicKey, listeners) 45 | } 46 | 47 | // GetNext - fetch the data for the next node in the ring for a given public key 48 | func GetNext(publicKey []byte) ([]byte, []byte, time.Time, error) { 49 | return globalData.receptors.Next(publicKey) 50 | } 51 | -------------------------------------------------------------------------------- /announce/announcer_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package announce_test 7 | 8 | import ( 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/golang/mock/gomock" 14 | "github.com/stretchr/testify/assert" 15 | 16 | "github.com/bitmark-inc/bitmarkd/announce" 17 | "github.com/bitmark-inc/bitmarkd/announce/fixtures" 18 | "github.com/bitmark-inc/bitmarkd/announce/mocks" 19 | ) 20 | 21 | func TestSendRegistration(t *testing.T) { 22 | fixtures.SetupTestLogger() 23 | defer fixtures.TeardownTestLogger() 24 | 25 | f := func(_ string) ([]string, error) { return []string{}, nil } 26 | 27 | _ = announce.Initialise("domain.not.exist", "cache", f) 28 | defer announce.Finalise() 29 | 30 | // make sure background jobs already finish first round, so 31 | // no logger will be called 32 | time.Sleep(20 * time.Millisecond) 33 | 34 | ctl := gomock.NewController(t) 35 | defer ctl.Finish() 36 | 37 | e := fmt.Errorf("wrong") 38 | c := mocks.NewMockClient(ctl) 39 | c.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(e).Times(1) 40 | 41 | err := announce.SendRegistration(c, "") 42 | assert.Equal(t, e, err, "wrong SendRegistration") 43 | } 44 | -------------------------------------------------------------------------------- /announce/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package announce - network announcements 7 | // 8 | // The DNS TXT record format is a set of space separated key=value pairs 9 | // 10 | // Key Value 11 | // ======= ========= 12 | // bitmark v3 13 | // a Public IP addresses as IPv4;[IPv6] 14 | // c Peer-To-Peer port number (decimal) 15 | // r RPC port number (decimal) 16 | // f SHA3 fingerprint of the certificate used by RPC connection for TLS verification (hex) 17 | // p Public key of the P2P connection for ZeroMQ encryption (hex) 18 | package announce 19 | -------------------------------------------------------------------------------- /announce/domain/lookuper.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package domain 7 | 8 | import ( 9 | "strings" 10 | 11 | "github.com/bitmark-inc/bitmarkd/fault" 12 | "github.com/bitmark-inc/logger" 13 | ) 14 | 15 | // Lookuper - interface to lookup DNS record 16 | type Lookuper interface { 17 | Lookup(string) ([]DnsTXT, error) 18 | } 19 | 20 | type lookuper struct { 21 | log *logger.L 22 | f func(string) ([]string, error) 23 | } 24 | 25 | // Lookup - query DNS TXT record 26 | func (l *lookuper) Lookup(domainName string) ([]DnsTXT, error) { 27 | log := l.log 28 | var result []DnsTXT 29 | if domainName == "" { 30 | log.Error("invalid node domain") 31 | return result, fault.InvalidNodeDomain 32 | } 33 | 34 | txts, err := l.f(domainName) 35 | if err != nil { 36 | log.Errorf("lookup TXT record error: %s", err) 37 | return result, err 38 | } 39 | 40 | for i, t := range txts { 41 | t = strings.TrimSpace(t) 42 | txt, err := Parse(t) 43 | 44 | if err != nil { 45 | log.Debugf("ignore TXT[%d]: %q error: %s", i, t, err) 46 | } else { 47 | log.Infof("process TXT[%d]: %q", i, t) 48 | log.Infof("result[%d]: IPv4: %q IPv6: %q rpc: %d connect: %d", i, txt.IPv4, txt.IPv6, txt.RPCPort, txt.ConnectPort) 49 | log.Infof("result[%d]: peer public key: %x", i, txt.PublicKey) 50 | log.Infof("result[%d]: rpc fingerprint: %x", i, txt.CertificateFingerprint) 51 | 52 | if txt.IPv4 == nil && txt.IPv6 == nil { 53 | log.Debugf("result[%d]: ignoring invalid record", i) 54 | } else { 55 | result = append(result, *txt) 56 | } 57 | } 58 | } 59 | 60 | return result, nil 61 | } 62 | 63 | // NewLookuper - new Lookuper interface 64 | func NewLookuper(log *logger.L, f func(string) ([]string, error)) Lookuper { 65 | return &lookuper{ 66 | log: log, 67 | f: f, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /announce/fingerprint/fingerprint.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package fingerprint 7 | 8 | import "encoding/hex" 9 | 10 | // type for SHA3 fingerprints 11 | type Fingerprint [32]byte 12 | 13 | // MarshalText - convert fingerprint to little endian hex text 14 | func (fingerprint Fingerprint) MarshalText() ([]byte, error) { 15 | size := hex.EncodedLen(len(fingerprint)) 16 | buffer := make([]byte, size) 17 | hex.Encode(buffer, fingerprint[:]) 18 | return buffer, nil 19 | } 20 | -------------------------------------------------------------------------------- /announce/fingerprint/fingerprint_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package fingerprint_test 7 | 8 | import ( 9 | "encoding/hex" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | 14 | "github.com/bitmark-inc/bitmarkd/announce/fingerprint" 15 | ) 16 | 17 | func TestMarshalText(t *testing.T) { 18 | f := fingerprint.Fingerprint{1, 2, 3, 4, 5} 19 | 20 | size := hex.EncodedLen(len(f)) 21 | expected := make([]byte, size) 22 | hex.Encode(expected, f[:]) 23 | 24 | marshaled, _ := f.MarshalText() 25 | 26 | assert.Equal(t, expected, marshaled, "wrong MarshalText") 27 | } 28 | -------------------------------------------------------------------------------- /announce/fixtures/fixtures.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package fixtures 7 | 8 | import ( 9 | "fmt" 10 | "os" 11 | 12 | zmq "github.com/pebbe/zmq4" 13 | 14 | "github.com/bitmark-inc/bitmarkd/util" 15 | "github.com/bitmark-inc/logger" 16 | ) 17 | 18 | const ( 19 | dir = "testing" 20 | LogCategory = "testing" 21 | ) 22 | 23 | var ( 24 | Listener1 []byte 25 | Listener2 []byte 26 | PublicKey1 []byte 27 | PublicKey2 []byte 28 | PublicKey3 []byte 29 | ) 30 | 31 | func init() { 32 | c, _ := util.NewConnection("127.0.0.1:1234") 33 | Listener1 = make([]byte, 0, 100) 34 | Listener1 = append(Listener1, c.Pack()...) 35 | 36 | c, _ = util.NewConnection("192.168.0.1:5678") 37 | Listener2 = make([]byte, 0, 100) 38 | Listener2 = append(Listener2, c.Pack()...) 39 | 40 | tmp, _, _ := zmq.NewCurveKeypair() 41 | PublicKey1 = []byte(zmq.Z85decode(tmp)) 42 | 43 | tmp, _, _ = zmq.NewCurveKeypair() 44 | PublicKey2 = []byte(zmq.Z85decode(tmp)) 45 | 46 | tmp, _, _ = zmq.NewCurveKeypair() 47 | PublicKey3 = []byte(zmq.Z85decode(tmp)) 48 | } 49 | 50 | func SetupTestLogger() { 51 | removeFiles() 52 | _ = os.Mkdir(dir, 0o700) 53 | 54 | logging := logger.Configuration{ 55 | Directory: dir, 56 | File: fmt.Sprintf("%s.log", LogCategory), 57 | Size: 1048576, 58 | Count: 10, 59 | Console: false, 60 | Levels: map[string]string{ 61 | logger.DefaultTag: "critical", 62 | }, 63 | } 64 | 65 | // start logging 66 | _ = logger.Initialise(logging) 67 | } 68 | 69 | func TeardownTestLogger() { 70 | logger.Finalise() 71 | removeFiles() 72 | } 73 | 74 | func removeFiles() { 75 | err := os.RemoveAll(dir) 76 | if err != nil { 77 | fmt.Println("remove dir with error: ", err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /announce/helper/helper.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package helper 7 | 8 | import "time" 9 | 10 | // ResetFutureTimestampToNow - reset future timestamp to now 11 | func ResetFutureTimestampToNow(timestamp uint64) time.Time { 12 | ts := time.Unix(int64(timestamp), 0) 13 | now := time.Now() 14 | if now.Before(ts) { 15 | return now 16 | } 17 | return ts 18 | } 19 | 20 | // IsExpiredAfterDuration- is peer expired from time 21 | func IsExpiredAfterDuration(timestamp time.Time, d time.Duration) bool { 22 | return timestamp.Add(d).Before(time.Now()) 23 | } 24 | -------------------------------------------------------------------------------- /announce/helper/helper_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package helper_test 7 | 8 | import ( 9 | "testing" 10 | "time" 11 | 12 | "github.com/stretchr/testify/assert" 13 | 14 | "github.com/bitmark-inc/bitmarkd/announce/helper" 15 | ) 16 | 17 | func TestResetFutureTimestampToNow(t *testing.T) { 18 | now := time.Now() 19 | actual := helper.ResetFutureTimestampToNow(uint64(now.Add(time.Minute).Unix())) 20 | assert.Equal(t, true, actual.After(now), "reset time") 21 | assert.Equal(t, true, actual.Add(-1*time.Millisecond).Before(now), "reset time") 22 | } 23 | 24 | func TestResetFutureTimestampToNowWhenPast(t *testing.T) { 25 | prev := time.Now().Add(-1 * time.Minute) 26 | actual := helper.ResetFutureTimestampToNow(uint64(prev.Unix())) 27 | assert.Equal(t, time.Unix(int64(prev.Unix()), 0), actual, "wrong previous time") 28 | } 29 | 30 | func TestIsExpiredAfterDuration(t *testing.T) { 31 | now := time.Now() 32 | actual := helper.IsExpiredAfterDuration(now.Add(-59*time.Second), 60*time.Second) 33 | assert.False(t, actual, "wrong expire") 34 | 35 | actual = helper.IsExpiredAfterDuration(now.Add(-60*time.Second), 59*time.Second) 36 | assert.True(t, actual, "wrong expire") 37 | } 38 | -------------------------------------------------------------------------------- /announce/id/id.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package id 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | ) 12 | 13 | type ID []byte 14 | 15 | // Compare - public key comparison for AVL interface 16 | func (i ID) Compare(q interface{}) int { 17 | return bytes.Compare(i, q.(ID)) 18 | } 19 | 20 | // String - public key string convert for AVL interface 21 | func (i ID) String() string { 22 | return fmt.Sprintf("%x", []byte(i)) 23 | } 24 | -------------------------------------------------------------------------------- /announce/id/id_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package id_test 7 | 8 | import ( 9 | "fmt" 10 | "testing" 11 | 12 | "github.com/bitmark-inc/bitmarkd/announce/id" 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestCompare(t *testing.T) { 17 | id1 := id.ID("THIS IS CAPITAL") 18 | id2 := id.ID("this is normal") 19 | id3 := id.ID("Same TEXT") 20 | id4 := id.ID("Same TEXT") 21 | 22 | assert.Equal(t, -1, id1.Compare(id2), "wrong comparison") 23 | assert.Equal(t, 1, id2.Compare(id1), "wrong comparison") 24 | 25 | //lint:ignore dupArg // really check the argument against itself 26 | assert.Equal(t, 0, id3.Compare(id3), "wrong comparison") 27 | 28 | assert.Equal(t, 0, id3.Compare(id4), "wrong comparison") 29 | assert.Equal(t, 0, id4.Compare(id3), "wrong comparison") 30 | 31 | } 32 | 33 | func TestString(t *testing.T) { 34 | id1 := id.ID("test string") 35 | expected := fmt.Sprintf("%x", []byte("test string")) 36 | 37 | assert.Equal(t, expected, id1.String(), "wrong string") 38 | } 39 | -------------------------------------------------------------------------------- /announce/parameter/parameter.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package parameter 7 | 8 | import "time" 9 | 10 | const ( 11 | InitialiseInterval = 2 * time.Minute // startup delay before first send 12 | PollingInterval = 11 * time.Minute // regular polling time 13 | BroadcastInterval = 11 * time.Minute // regular polling time 14 | ExpiryInterval = 5 * BroadcastInterval // if no responses received within this time, delete the entry 15 | RebroadcastInterval = 7 * time.Minute // to prevent too frequent rebroadcasts 16 | ) 17 | -------------------------------------------------------------------------------- /announce/rpc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package announce 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/announce/fingerprint" 10 | "github.com/bitmark-inc/bitmarkd/announce/rpc" 11 | ) 12 | 13 | // SetRPC - set this node's rpc announcement data 14 | func SetRPC(fin fingerprint.Fingerprint, listeners []byte) error { 15 | return globalData.rpcs.Set(fin, listeners) 16 | } 17 | 18 | // AddRPC - add an remote RPC listener 19 | // returns: 20 | // 21 | // true if this was a new/updated entry 22 | // false if the update was within the limits (to prevent continuous relaying) 23 | func AddRPC(fin []byte, listeners []byte, timestamp uint64) bool { 24 | return globalData.rpcs.Add(fin, listeners, timestamp) 25 | } 26 | 27 | // FetchRPCs - fetch some records 28 | func FetchRPCs(start uint64, count int) ([]rpc.Entry, uint64, error) { 29 | return globalData.rpcs.Fetch(start, count) 30 | } 31 | -------------------------------------------------------------------------------- /asset/asset_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package asset 7 | -------------------------------------------------------------------------------- /asset/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package asset - Cache for assets 7 | // 8 | // temporary store assets just received until they are: 9 | // a. verified by having a corresponding issue verified 10 | // b. confirmed by having a block broadcast containing them 11 | // c. expired because no longer referenced by any issues 12 | // i.e. all isues were expired 13 | package asset 14 | -------------------------------------------------------------------------------- /avl/check.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | import ( 9 | "fmt" 10 | ) 11 | 12 | // CheckUp - check the up pointers for consistency 13 | func (tree *Tree) CheckUp() bool { 14 | return checkUp(tree.root, nil) 15 | } 16 | 17 | // internal: consistency checker 18 | func checkUp(p *Node, up *Node) bool { 19 | if p == nil { 20 | return true 21 | } 22 | if p.up != up { 23 | fmt.Printf("fail at node: %v actual: %v expected: %v\n", p.key, p.up.key, up.key) 24 | return false 25 | } 26 | if !checkUp(p.left, p) { 27 | return false 28 | } 29 | return checkUp(p.right, p) 30 | } 31 | 32 | // CheckCounts - check left and right node counts are ok 33 | func (tree *Tree) CheckCounts() bool { 34 | b, _ := checkCounts(tree.root) 35 | return b 36 | } 37 | 38 | func checkCounts(p *Node) (bool, int) { 39 | if p == nil { 40 | return true, 0 41 | } 42 | bl := true 43 | nl := 0 44 | if p.left != nil { 45 | bl, nl = checkCounts(p.left) 46 | if p.leftNodes != nl { 47 | fmt.Printf("fail at node: %v left actual: %d record: %d\n", p.key, nl, p.leftNodes) 48 | bl = false 49 | } 50 | } 51 | br := true 52 | nr := 0 53 | if p.right != nil { 54 | br, nr = checkCounts(p.right) 55 | if p.rightNodes != nr { 56 | fmt.Printf("fail at node: %v right actual: %d record: %d\n", p.key, nr, p.rightNodes) 57 | br = false 58 | } 59 | } 60 | return bl && br, 1 + nl + nr 61 | } 62 | -------------------------------------------------------------------------------- /avl/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package avl - an AVL balanced tree with the addition of parent 7 | // pointers to allow iteration through the nodes 8 | // 9 | // Note: an individual tree is not thread safe, so either access only 10 | // 11 | // in a single go routine or use mutex/rwmutex to restrict 12 | // access. 13 | // 14 | // The base algorithm was described in an old book by Niklaus Wirth 15 | // called Algorithms + Data Structures = Programs. 16 | // 17 | // This version allows for data associated with key, which can be 18 | // overwritten by an insert with the same key. Also delete no does 19 | // not copy data around so that previous nodes can be deleted during 20 | // iteration. 21 | package avl 22 | -------------------------------------------------------------------------------- /avl/get.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | // Get - access specific item by index 9 | func (tree *Tree) Get(index int) *Node { 10 | if index < 0 || index >= tree.Count() { 11 | return nil 12 | } 13 | return get(index, tree.root) 14 | } 15 | 16 | func get(index int, tree *Node) *Node { 17 | if tree == nil { 18 | return nil 19 | } 20 | 21 | nl := tree.leftNodes 22 | 23 | if index < nl { 24 | return get(index, tree.left) 25 | } 26 | if index > nl { 27 | // subtract left nodes + 1 (for this node) 28 | return get(index-nl-1, tree.right) 29 | } 30 | return tree 31 | } 32 | -------------------------------------------------------------------------------- /avl/iterator.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | // First - return the node with the lowest key value 9 | func (tree *Tree) First() *Node { 10 | return tree.root.first() 11 | } 12 | 13 | // internal: lowest node in a sub-tree 14 | func (tree *Node) first() *Node { 15 | if tree == nil { 16 | return nil 17 | } 18 | for tree.left != nil { 19 | tree = tree.left 20 | } 21 | return tree 22 | } 23 | 24 | // Last - return the node with the highest key value 25 | func (tree *Tree) Last() *Node { 26 | return tree.root.last() 27 | } 28 | 29 | // internal: highest node in a sub-tree 30 | func (tree *Node) last() *Node { 31 | if tree == nil { 32 | return nil 33 | } 34 | for tree.right != nil { 35 | tree = tree.right 36 | } 37 | return tree 38 | } 39 | 40 | // Next - given a node, return the node with the next highest key 41 | // value or nil if no more nodes. 42 | func (tree *Node) Next() *Node { 43 | if tree.right == nil { 44 | key := tree.key 45 | for { 46 | tree = tree.up 47 | if tree == nil { 48 | return nil 49 | } 50 | if tree.key.Compare(key) == 1 { // tree.key > key 51 | return tree 52 | } 53 | } 54 | } 55 | return tree.right.first() 56 | } 57 | 58 | // Prev - given a node, return the node with the lowest key value or 59 | // nil if no more nodes 60 | func (tree *Node) Prev() *Node { 61 | if tree.left == nil { 62 | key := tree.key 63 | for { 64 | tree = tree.up 65 | if tree == nil { 66 | return nil 67 | } 68 | if -1 == tree.key.Compare(key) { // tree.key < key 69 | return tree 70 | } 71 | } 72 | } 73 | return tree.left.last() 74 | } 75 | -------------------------------------------------------------------------------- /avl/print.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | import ( 9 | "fmt" 10 | ) 11 | 12 | // to control the print routine 13 | type branch int 14 | 15 | const ( 16 | root branch = iota 17 | left branch = iota 18 | right branch = iota 19 | ) 20 | 21 | // Print - display an ASCII graphic representation of the tree 22 | func (tree *Tree) Print(printData bool) int { 23 | return printTree(tree.root, "", root, printData) 24 | } 25 | 26 | // internal print - returns the maximum depth of the tree 27 | func printTree(tree *Node, prefix string, br branch, printData bool) int { 28 | if tree == nil { 29 | return 0 30 | } 31 | rd := 0 32 | ld := 0 33 | if tree.right != nil { 34 | t := " " 35 | if left == br { 36 | t = "| " 37 | } 38 | rd = printTree(tree.right, prefix+t, right, printData) 39 | } 40 | switch br { 41 | case root: 42 | fmt.Printf("%s|------+ ", prefix) 43 | case left: 44 | fmt.Printf("%s\\------+ ", prefix) 45 | case right: 46 | fmt.Printf("%s/------+ ", prefix) 47 | } 48 | up := interface{}(nil) 49 | if tree.up != nil { 50 | up = tree.up.key 51 | } 52 | if printData { 53 | fmt.Printf("%q → %q ^%v %+2d/[%d,%d]\n", tree.key, tree.value, up, tree.balance, tree.leftNodes, tree.rightNodes) 54 | } else { 55 | fmt.Printf("%q ^%v\n", tree.key, up) 56 | } 57 | if tree.left != nil { 58 | t := " " 59 | if right == br { 60 | t = "| " 61 | } 62 | ld = printTree(tree.left, prefix+t, left, printData) 63 | } 64 | if rd > ld { 65 | return 1 + rd 66 | } else { 67 | return 1 + ld 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /avl/search.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | // Search - find a specific item 9 | func (tree *Tree) Search(key Item) (*Node, int) { 10 | return search(key, tree.root, 0) 11 | } 12 | 13 | func search(key Item, tree *Node, index int) (*Node, int) { 14 | if tree == nil { 15 | return nil, -1 16 | } 17 | 18 | switch tree.key.Compare(key) { 19 | case +1: // tree.key > key 20 | return search(key, tree.left, index) 21 | case -1: // tree.key < key 22 | return search(key, tree.right, index+tree.leftNodes+1) 23 | default: 24 | return tree, index + tree.leftNodes 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /avl/setup.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package avl 7 | 8 | // Tree - type to hold the root node of a tree 9 | type Tree struct { 10 | root *Node 11 | count int 12 | } 13 | 14 | // New - create an initially empty tree 15 | func New() *Tree { 16 | return &Tree{ 17 | root: nil, 18 | count: 0, 19 | } 20 | } 21 | 22 | // IsEmpty - true if tree contains some data 23 | func (tree *Tree) IsEmpty() bool { 24 | return tree.root == nil 25 | } 26 | 27 | // Count - number of nodes currently in the tree 28 | func (tree *Tree) Count() int { 29 | return tree.count 30 | } 31 | 32 | // Root - return the root node of the tree 33 | func (tree *Tree) Root() *Node { 34 | return tree.root 35 | } 36 | 37 | // GetChildrenByDepth - returns all children in a specific depth of a tree 38 | func (p *Node) GetChildrenByDepth(depth uint) []*Node { 39 | nodes := []*Node{} 40 | 41 | if depth == 0 { 42 | nodes = []*Node{p} 43 | } else { 44 | left := p.left 45 | right := p.right 46 | if left != nil { 47 | nodes = append(nodes, left.GetChildrenByDepth(depth-1)...) 48 | } 49 | 50 | if right != nil { 51 | nodes = append(nodes, right.GetChildrenByDepth(depth-1)...) 52 | } 53 | } 54 | return nodes 55 | } 56 | 57 | // Key - read the key from a node item 58 | func (p *Node) Key() Item { 59 | return p.key 60 | } 61 | 62 | // Value - read the value from a node item 63 | func (p *Node) Value() interface{} { 64 | return p.value 65 | } 66 | 67 | // Parent - return parent node of a node 68 | func (p *Node) Parent() *Node { 69 | return p.up 70 | } 71 | 72 | // Depth - get the depth of a node 73 | func (p *Node) Depth() uint { 74 | count := uint(0) 75 | parent := p.up 76 | for parent != nil { 77 | count += 1 78 | parent = parent.up 79 | } 80 | return count 81 | } 82 | -------------------------------------------------------------------------------- /background/background.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package background 7 | 8 | import ( 9 | "sync" 10 | ) 11 | 12 | // the shutdown and completed type for a background 13 | type shutdown struct { 14 | shutdown chan struct{} 15 | finished chan struct{} 16 | } 17 | 18 | // T - handle type for the stop 19 | type T struct { 20 | sync.WaitGroup 21 | s []shutdown 22 | } 23 | 24 | // Process - type signature for background process 25 | // and type that implements this Run is a process 26 | type Process interface { 27 | Run(args interface{}, shutdown <-chan struct{}) 28 | } 29 | 30 | // Processes - list of processes to start 31 | type Processes []Process 32 | 33 | // Start - start up a set of background processes 34 | // all with the same arg value 35 | func Start(processes Processes, args interface{}) *T { 36 | 37 | register := new(T) 38 | register.WaitGroup = sync.WaitGroup{} 39 | register.s = make([]shutdown, len(processes)) 40 | 41 | // start each background 42 | for i, p := range processes { 43 | shutdown := make(chan struct{}) 44 | finished := make(chan struct{}) 45 | register.s[i].shutdown = shutdown 46 | register.s[i].finished = finished 47 | register.Add(1) 48 | go func(p Process, shutdown <-chan struct{}, finished chan<- struct{}) { 49 | p.Run(args, shutdown) 50 | register.Done() 51 | // flag for the stop routine to wait for shutdown 52 | close(finished) 53 | }(p, shutdown, finished) 54 | } 55 | return register 56 | } 57 | 58 | // Stop - stop a set of background processes 59 | func (t *T) Stop() { 60 | 61 | if t == nil { 62 | return 63 | } 64 | 65 | // trigger shutdown of all background tasks 66 | for _, shutdown := range t.s { 67 | close(shutdown.shutdown) 68 | } 69 | } 70 | 71 | // StopAndWait will notify all processes to shutdown by closing shutdown channel 72 | // and wait until all processes be stopped. 73 | func (t *T) StopAndWait() { 74 | t.Stop() 75 | t.Wait() 76 | } 77 | -------------------------------------------------------------------------------- /background/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package background - Simple skeleton for background processes 7 | package background 8 | -------------------------------------------------------------------------------- /background/example_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package background_test 7 | 8 | import ( 9 | "fmt" 10 | "time" 11 | 12 | "github.com/bitmark-inc/bitmarkd/background" 13 | ) 14 | 15 | type theState struct { 16 | count int 17 | } 18 | 19 | func Example() { 20 | 21 | proc := &theState{ 22 | count: 10, 23 | } 24 | 25 | // list of background processes to start 26 | processes := background.Processes{ 27 | proc, 28 | } 29 | 30 | p := background.Start(processes, nil) 31 | time.Sleep(time.Second) 32 | p.Stop() 33 | } 34 | 35 | func (state *theState) Run(args interface{}, shutdown <-chan struct{}) { 36 | 37 | fmt.Printf("initialise\n") 38 | 39 | loop: 40 | for { 41 | select { 42 | case <-shutdown: 43 | break loop 44 | default: 45 | } 46 | 47 | state.count += 1 48 | time.Sleep(time.Millisecond) 49 | } 50 | 51 | fmt.Printf("finalise\n") 52 | } 53 | -------------------------------------------------------------------------------- /block/block_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package block 7 | -------------------------------------------------------------------------------- /block/blockstore.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package block 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/messagebus" 10 | "github.com/bitmark-inc/logger" 11 | ) 12 | 13 | type blockstore struct { 14 | log *logger.L 15 | } 16 | 17 | // initialise the broadcaster 18 | func (blk *blockstore) initialise() error { 19 | 20 | log := logger.New("blockstore") 21 | blk.log = log 22 | 23 | log.Info("initialising…") 24 | 25 | return nil 26 | } 27 | 28 | // wait for new blocks 29 | func (blk *blockstore) Run(args interface{}, shutdown <-chan struct{}) { 30 | 31 | log := blk.log 32 | 33 | log.Info("starting…") 34 | 35 | queue := messagebus.Bus.Blockstore.Chan() 36 | 37 | loop: 38 | for { 39 | log.Debug("waiting…") 40 | select { 41 | case <-shutdown: 42 | break loop 43 | case item := <-queue: 44 | log.Infof("received: %s data: %x", item.Command, item.Parameters) 45 | blk.process(&item) 46 | } 47 | } 48 | messagebus.Bus.Blockstore.Release() 49 | } 50 | 51 | // process the received block 52 | func (blk *blockstore) process(item *messagebus.Message) { 53 | 54 | log := blk.log 55 | 56 | if len(item.Parameters) == 1 { 57 | packedBlock := item.Parameters[0] 58 | err := StoreIncoming(packedBlock, nil, RescanVerified) 59 | if err == nil { 60 | // broadcast this packedBlock to peers if the block was valid 61 | messagebus.Bus.Broadcast.Send("block", packedBlock) 62 | } else { 63 | log.Debugf("store block: %x error: %s", packedBlock, err) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /block/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package block - process and store the incoming block 7 | package block 8 | -------------------------------------------------------------------------------- /block/recovery.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package block 7 | 8 | import ( 9 | "encoding/binary" 10 | 11 | "github.com/bitmark-inc/bitmarkd/blockrecord" 12 | "github.com/bitmark-inc/bitmarkd/storage" 13 | ) 14 | 15 | func doBlockHeaderHash() error { 16 | return storage.Pool.Blocks.NewFetchCursor().Map(recoverBlockHeaderHash) 17 | } 18 | 19 | func recoverBlockHeaderHash(blockNumberBytes []byte, packedBlock []byte) error { 20 | globalData.Lock() 21 | defer globalData.Unlock() 22 | 23 | // TODO: decide if we need to disable reservoir when migrating the block db 24 | // reservoir.Disable() 25 | // defer reservoir.Enable() 26 | 27 | // reservoir.ClearSpend() 28 | trx, err := storage.NewDBTransaction() 29 | if err != nil { 30 | return err 31 | } 32 | 33 | blockNumber := binary.BigEndian.Uint64(blockNumberBytes) 34 | 35 | blockHeaderHashBytes := trx.Get(storage.Pool.BlockHeaderHash, blockNumberBytes) 36 | if blockHeaderHashBytes == nil { 37 | digest, err := blockrecord.ComputeHeaderHash(packedBlock) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | trx.Put(storage.Pool.BlockHeaderHash, blockNumberBytes, digest[:], []byte{}) 43 | } 44 | trx.Commit() 45 | 46 | globalData.log.Debugf("rebuilt block: %d", blockNumber) 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /blockdigest/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package blockdigest - implementation block header hashing 7 | // 8 | // using a memory intensive argon2-d algorithm 9 | package blockdigest 10 | -------------------------------------------------------------------------------- /blockdump/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2021 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package blockdump - extract a range of blocks and their transactions 7 | // 8 | // used by the dump commandline option and the Node.BlockDump 9 | package blockdump 10 | -------------------------------------------------------------------------------- /blockheader/common_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package blockheader_test 7 | 8 | import ( 9 | "os" 10 | "testing" 11 | 12 | "github.com/bitmark-inc/bitmarkd/blockheader" 13 | "github.com/bitmark-inc/logger" 14 | ) 15 | 16 | // remove all files created by test 17 | func removeFiles() { 18 | os.RemoveAll("test.log") 19 | } 20 | 21 | // configure for testing 22 | func setup(t *testing.T) { 23 | removeFiles() 24 | 25 | logger.Initialise(logger.Configuration{ 26 | Directory: ".", 27 | File: "test.log", 28 | Size: 50000, 29 | Count: 10, 30 | }) 31 | 32 | err := blockheader.Initialise() 33 | if err != nil { 34 | t.Fatalf("initialise error: %s", err) 35 | } 36 | } 37 | 38 | // post test cleanup 39 | func teardown(t *testing.T) { 40 | err := blockheader.Finalise() 41 | if err != nil { 42 | t.Fatalf("finalise error: %s", err) 43 | } 44 | logger.Finalise() 45 | removeFiles() 46 | } 47 | -------------------------------------------------------------------------------- /blockheader/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package blockheader - current block header data 7 | package blockheader 8 | -------------------------------------------------------------------------------- /blockheader/header_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package blockheader_test 7 | 8 | import ( 9 | "testing" 10 | "time" 11 | 12 | "github.com/bitmark-inc/bitmarkd/blockdigest" 13 | "github.com/bitmark-inc/bitmarkd/blockheader" 14 | ) 15 | 16 | func TestHeader(t *testing.T) { 17 | setup(t) 18 | defer teardown(t) 19 | 20 | someHeight := uint64(1234567890) 21 | someDigest := blockdigest.Digest{ 22 | 0x2b, 0xa1, 0x2b, 0xa1, 0x54, 0x2b, 0xa1, 0x54, 23 | 0x14, 0x46, 0x74, 0x29, 0x1d, 0x29, 0x1d, 0x29, 24 | 0x2b, 0xa1, 0x2b, 0xa1, 0x54, 0x2b, 0xa1, 0x54, 25 | 0x14, 0x46, 0x74, 0x29, 0x1d, 0x29, 0x1d, 0x29, 26 | } 27 | someVersion := uint16(15) 28 | someTimestamp := uint64(time.Now().Unix()) 29 | 30 | blockheader.Set(someHeight, someDigest, someVersion, someTimestamp) 31 | 32 | height, digest, version, timestamp := blockheader.Get() 33 | 34 | if height != someHeight { 35 | t.Errorf("height: actual: %d expected: %d", height, someHeight) 36 | } 37 | if digest != someDigest { 38 | t.Errorf("digest: actual: %d expected: %d", digest, someDigest) 39 | } 40 | if version != someVersion { 41 | t.Errorf("version: actual: %d expected: %d", version, someVersion) 42 | } 43 | if timestamp != someTimestamp { 44 | t.Errorf("timestamp: actual: %d expected: %d", timestamp, someTimestamp) 45 | } 46 | 47 | digest, height = blockheader.GetNew() 48 | 49 | if digest != someDigest { 50 | t.Errorf("digest: actual: %d expected: %d", digest, someDigest) 51 | } 52 | 53 | if height != someHeight+1 { 54 | t.Errorf("height: actual: %d expected: %d", height, someHeight+1) 55 | } 56 | 57 | height = blockheader.Height() 58 | if height != someHeight { 59 | t.Errorf("height: actual: %d expected: %d", height, someHeight) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /blockrecord/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package blockrecord - the structure of the block header 7 | // 8 | // includes functions to pack/unpack []byte form 9 | package blockrecord 10 | -------------------------------------------------------------------------------- /blockrecord/nonce.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package blockrecord 7 | 8 | import ( 9 | "encoding/binary" 10 | "encoding/hex" 11 | ) 12 | 13 | // NonceType - for header nonce field 14 | type NonceType uint64 15 | 16 | // MarshalText - convert a nonce to little endian hex for JSON 17 | func (nonce NonceType) MarshalText() ([]byte, error) { 18 | 19 | bits := make([]byte, 8) 20 | binary.LittleEndian.PutUint64(bits, uint64(nonce)) 21 | 22 | size := hex.EncodedLen(len(bits)) 23 | buffer := make([]byte, size) 24 | hex.Encode(buffer, bits) 25 | return buffer, nil 26 | } 27 | 28 | // UnmarshalText - convert a nonce little endian hex string to nonce value 29 | func (nonce *NonceType) UnmarshalText(b []byte) error { 30 | buffer := make([]byte, hex.DecodedLen(len(b))) 31 | _, err := hex.Decode(buffer, b) 32 | if err != nil { 33 | return err 34 | } 35 | *nonce = NonceType(binary.LittleEndian.Uint64(buffer)) 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /blockrecord/nonce_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package blockrecord_test 7 | 8 | import ( 9 | "encoding/json" 10 | "testing" 11 | 12 | "github.com/bitmark-inc/bitmarkd/blockrecord" 13 | ) 14 | 15 | // test JSON conversion 16 | func TestInitialBits(t *testing.T) { 17 | 18 | nonces := []blockrecord.NonceType{ 19 | 0x1234567890abcdef, 20 | 0x1234567890abcdef, 21 | 0x1234567890abcdef, 22 | } 23 | 24 | for i, expected := range nonces { 25 | 26 | buffer, err := json.Marshal(expected) 27 | if err != nil { 28 | t.Fatalf("%d: JSON encode error: %s", i, err) 29 | } 30 | 31 | var actual blockrecord.NonceType 32 | err = json.Unmarshal(buffer, &actual) 33 | if err != nil { 34 | t.Fatalf("%d: JSON decode error: %s", i, err) 35 | } 36 | 37 | if actual != expected { 38 | t.Errorf("%d: JSON actual: %016x expected: %016x", i, actual, expected) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chain/chain_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package chain 7 | -------------------------------------------------------------------------------- /chain/chains.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package chain 7 | 8 | // names of all chains 9 | const ( 10 | Bitmark = "bitmark" 11 | Testing = "testing" 12 | Local = "local" 13 | ) 14 | 15 | // Valid - validate a chain name 16 | func Valid(name string) bool { 17 | switch name { 18 | case Bitmark, Testing, Local: 19 | return true 20 | default: 21 | return false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chain/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package chain - simple module to list the supported chains 7 | package chain 8 | -------------------------------------------------------------------------------- /command/bitmark-cli/.gitignore: -------------------------------------------------------------------------------- 1 | bitmark-cli 2 | *~ 3 | \#* 4 | -------------------------------------------------------------------------------- /command/bitmark-cli/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 Bitmark Inc. 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /command/bitmark-cli/README.md: -------------------------------------------------------------------------------- 1 | #bitmark-cli 2 | command line interface for issue, transfer bitmark 3 | 4 | ``` 5 | usage: bitmark-cli [options] [params] 6 | --help -h print this message 7 | --verbose -v verbose result 8 | --config=DIR -c DIR *bitmark-cli config folder 9 | --identity=NAME -i NAME identity name [bitmark-identity] 10 | 11 | command params: (* = required) 12 | setup initialise bitmark-cli configuration 13 | --network=NET -n NET bitmark|testing. Connect to which bitmark network [testing] 14 | --connect=HOST:PORT -x HOST:PORT *bitmarkd host/IP and port 15 | --description=TEXT -d TEXT *identity description 16 | 17 | generate new identity 18 | --description=TEXT -d TEXT *identity description 19 | 20 | issue create and issue bitmark 21 | --asset=NAME -a NAME *asset name 22 | --description=TEXT -d TEXT *asset description 23 | --fingerprint=TEXT -f TEXT *asset fingerprint 24 | --quantity=N -q N quantity to issue [1] 25 | 26 | transfer transfer bitmark 27 | --txid=HEX -t HEX *transaction id to transfer 28 | --receiver=NAME -r NAME *identity name to receive the transactoin 29 | 30 | info display bitmarkd status 31 | 32 | version display bitmark-cli version 33 | ``` 34 | -------------------------------------------------------------------------------- /command/bitmark-cli/agent.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "os/exec" 10 | ) 11 | 12 | const ( 13 | passwordTag = "bitmark-cli:password:" 14 | ) 15 | 16 | // expect to execute agent with parameters 17 | // --confirm=1 - for additional confirm 18 | // cache-id - alows password to be cached for a time 19 | // error-message - blank 20 | // prompt - names the identity 21 | // description - shows create/transfer operation 22 | func passwordFromAgent(name string, title string, agent string, clear bool) (string, error) { 23 | 24 | cacheId := passwordTag + name 25 | errorMessage := "" 26 | prompt := "Password for: " + name 27 | description := "Enter password to: " + title 28 | 29 | arguments := []string{} 30 | if clear { 31 | arguments = append(arguments, "--clear") 32 | } 33 | arguments = append(arguments, []string{ 34 | "--confirm=1", 35 | cacheId, 36 | errorMessage, 37 | prompt, 38 | description}...) 39 | 40 | out, err := exec.Command(agent, arguments...).Output() 41 | return string(out), err 42 | } 43 | -------------------------------------------------------------------------------- /command/bitmark-cli/configuration/configuration_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | -------------------------------------------------------------------------------- /command/bitmark-cli/configuration/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | -------------------------------------------------------------------------------- /command/bitmark-cli/configuration/salt.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | 8 | import ( 9 | "crypto/rand" 10 | "encoding/hex" 11 | 12 | "github.com/bitmark-inc/bitmarkd/fault" 13 | ) 14 | 15 | const ( 16 | saltSize = 32 17 | ) 18 | 19 | // Salt - type to hold a salt value 20 | type Salt [saltSize]byte 21 | 22 | // MakeSalt - create a salt using secure random number generator 23 | func MakeSalt() (*Salt, error) { 24 | salt := new(Salt) 25 | if _, err := rand.Read(salt[:]); err != nil { 26 | return nil, err 27 | } 28 | return salt, nil 29 | } 30 | 31 | // Bytes - convert a binary salt to byte slice 32 | func (salt Salt) Bytes() []byte { 33 | return salt[:] 34 | } 35 | 36 | // String - convert a binary salt to little endian hex string for use by the fmt package (for %s) 37 | func (salt Salt) String() string { 38 | return hex.EncodeToString(salt.Bytes()) 39 | } 40 | 41 | // MarshalText - convert salt to little endian hex text 42 | // 43 | // ***** possibly use NewEncoder and byte buffer to save copy 44 | func (salt *Salt) MarshalText() []byte { 45 | // encode to hex 46 | size := hex.EncodedLen(saltSize) 47 | buffer := make([]byte, size) 48 | hex.Encode(buffer, salt.Bytes()) 49 | 50 | return buffer 51 | } 52 | 53 | // UnmarshalText - convert little endian hex text into a salt 54 | func (salt *Salt) UnmarshalText(s []byte) error { 55 | buffer := make([]byte, hex.DecodedLen(len(s))) 56 | byteCount, err := hex.Decode(buffer, s) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | if saltSize != byteCount { 62 | return fault.UnmarshalTextFailed 63 | } 64 | copy(salt[:], buffer) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /command/bitmark-cli/configuration/salt_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | 8 | import ( 9 | "testing" 10 | ) 11 | 12 | // test Marshal and Unmarshal 13 | func TestSalt(t *testing.T) { 14 | salt, err := MakeSalt() 15 | if err != nil { 16 | t.Errorf("makeSalt fail: %s", err) 17 | } 18 | 19 | //t.Logf("salt: %s\n", salt) // enable for debugging 20 | 21 | marshalSalt := salt.MarshalText() 22 | 23 | //t.Logf("salt: %s\n", marshalSalt) // enable for debugging 24 | 25 | salt2 := new(Salt) 26 | salt2.UnmarshalText(marshalSalt) 27 | 28 | if salt.String() != salt2.String() { 29 | t.Errorf("unmarshal failed, %s != %s\n", salt.String(), salt2.String()) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /command/bitmark-cli/configuration/write.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "os" 12 | "strings" 13 | ) 14 | 15 | // Save - update configuration file with current data 16 | func Save(filename string, configuration *Configuration) error { 17 | 18 | tempFile := filename + ".new" 19 | previousFile := filename + ".bk" 20 | 21 | os.Remove(tempFile) 22 | 23 | f, err := os.Create(tempFile) 24 | if err != nil { 25 | fmt.Printf("Create file fail: %s\n", err) 26 | return err 27 | } 28 | 29 | enc := json.NewEncoder(f) 30 | enc.SetIndent("", " ") 31 | err = enc.Encode(configuration) 32 | if err != nil { 33 | f.Close() 34 | return err 35 | } 36 | 37 | f.Close() 38 | 39 | err = os.Remove(previousFile) 40 | if err != nil && !strings.Contains(err.Error(), "no such file") { 41 | return err 42 | } 43 | err = os.Rename(filename, previousFile) 44 | if err != nil && !strings.Contains(err.Error(), "no such file") { 45 | return err 46 | } 47 | err = os.Rename(tempFile, filename) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /command/bitmark-cli/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // to issue basic commands to a bitmarkd 7 | package main 8 | -------------------------------------------------------------------------------- /command/bitmark-cli/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | -------------------------------------------------------------------------------- /command/bitmark-cli/printjson.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "io" 12 | ) 13 | 14 | func printJson(handle io.Writer, message interface{}) error { 15 | 16 | prefix := "" 17 | indent := " " 18 | 19 | b, err := json.MarshalIndent(message, prefix, indent) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | fmt.Fprintf(handle, "%s\n", b) 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/balance.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/account" 10 | "github.com/bitmark-inc/bitmarkd/merkle" 11 | "github.com/bitmark-inc/bitmarkd/rpc/share" 12 | ) 13 | 14 | // BalanceData - the parameters for a balance request 15 | type BalanceData struct { 16 | Owner *account.Account 17 | ShareId string 18 | Count int 19 | } 20 | 21 | // GetBalance - retrieve some balance data 22 | func (client *Client) GetBalance(balanceConfig *BalanceData) (*share.BalanceReply, error) { 23 | 24 | var shareId merkle.Digest // if not present the all zero id 25 | if balanceConfig.ShareId != "" { 26 | if err := shareId.UnmarshalText([]byte(balanceConfig.ShareId)); err != nil { 27 | return nil, err 28 | } 29 | } 30 | 31 | balanceArgs := share.BalanceArguments{ 32 | Owner: balanceConfig.Owner, 33 | ShareId: shareId, 34 | Count: balanceConfig.Count, 35 | } 36 | 37 | client.printJson("Balance Request", balanceArgs) 38 | 39 | reply := &share.BalanceReply{} 40 | err := client.client.Call("Share.Balance", balanceArgs, reply) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | client.printJson("Balance Reply", reply) 46 | 47 | return reply, nil 48 | } 49 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/blockdecode.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/rpc/node" 10 | ) 11 | 12 | // BlockDecodeData - the parameters for a blockDecode request 13 | type BlockDecodeData struct { 14 | Packed []byte 15 | } 16 | 17 | // DecodeBlock - retrieve some blocks 18 | func (client *Client) DecodeBlock(blockDecodeConfig *BlockDecodeData) (*node.BlockDecodeReply, error) { 19 | 20 | blockDecodeArgs := node.BlockDecodeArguments{ 21 | Packed: blockDecodeConfig.Packed, 22 | } 23 | 24 | client.printJson("BlockDecode Request", blockDecodeArgs) 25 | 26 | reply := &node.BlockDecodeReply{} 27 | err := client.client.Call("Node.BlockDecode", blockDecodeArgs, reply) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | client.printJson("BlockDecode Reply", reply) 33 | 34 | return reply, nil 35 | } 36 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/blockdump.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/rpc/node" 10 | ) 11 | 12 | // BlockDumpData - the parameters for a blockDump request 13 | type BlockDumpData struct { 14 | Block uint64 15 | Count int 16 | Txs bool 17 | } 18 | 19 | // GetBlocks - retrieve some blocks 20 | func (client *Client) GetBlocks(blockDumpConfig *BlockDumpData) (*node.BlockDumpRangeReply, error) { 21 | 22 | blockDumpArgs := node.BlockDumpRangeArguments{ 23 | Height: blockDumpConfig.Block, 24 | Count: blockDumpConfig.Count, 25 | Txs: blockDumpConfig.Txs, 26 | } 27 | 28 | client.printJson("BlockDump Request", blockDumpArgs) 29 | 30 | reply := &node.BlockDumpRangeReply{} 31 | err := client.client.Call("Node.BlockDumpRange", blockDumpArgs, reply) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | client.printJson("BlockDump Reply", reply) 37 | 38 | return reply, nil 39 | } 40 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/countersign.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "encoding/hex" 10 | 11 | "golang.org/x/crypto/ed25519" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/configuration" 14 | "github.com/bitmark-inc/bitmarkd/fault" 15 | "github.com/bitmark-inc/bitmarkd/transactionrecord" 16 | ) 17 | 18 | // CountersignData - data for a countersignature request 19 | type CountersignData struct { 20 | Transaction string 21 | NewOwner *configuration.Private 22 | } 23 | 24 | // Countersign - countersign a transfer 25 | func (client *Client) Countersign(countersignConfig *CountersignData) (interface{}, error) { 26 | 27 | b, err := hex.DecodeString(countersignConfig.Transaction) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | bCs := append([]byte{}, b...) 33 | bCs=append(bCs, 0x01, 0x00) // one-byte countersignature to allow unpack to succeed 34 | r, _, err := transactionrecord.Packed(bCs).Unpack(client.testnet) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | // attach signature 40 | signature := ed25519.Sign(countersignConfig.NewOwner.PrivateKey.PrivateKeyBytes(), b) 41 | 42 | switch tx := r.(type) { 43 | case *transactionrecord.BitmarkTransferCountersigned: 44 | tx.Countersignature = signature 45 | return client.CountersignTransfer(tx) 46 | 47 | case *transactionrecord.BlockOwnerTransfer: 48 | tx.Countersignature = signature 49 | return client.CountersignBlockTransfer(tx) 50 | 51 | case *transactionrecord.ShareGrant: 52 | tx.Countersignature = signature 53 | return client.CountersignGrant(tx) 54 | 55 | case *transactionrecord.ShareSwap: 56 | tx.Countersignature = signature 57 | return client.CountersignSwap(tx) 58 | 59 | default: 60 | return nil, fault.NotACountersignableRecord 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package rpccalls - low level RPC calls to bitmarkd 7 | package rpccalls 8 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/info.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/rpc/node" 10 | ) 11 | 12 | // GetBitmarkInfo - request status from bitmarkd (must be matching version) 13 | func (client *Client) GetBitmarkInfo() (*node.InfoReply, error) { 14 | var reply node.InfoReply 15 | if err := client.client.Call("Node.Info", node.InfoArguments{}, &reply); err != nil { 16 | return nil, err 17 | } 18 | 19 | return &reply, nil 20 | } 21 | 22 | // GetBitmarkInfoCompat - request status from bitmarkd (any version) 23 | func (client *Client) GetBitmarkInfoCompat() (map[string]interface{}, error) { 24 | var reply map[string]interface{} 25 | if err := client.client.Call("Node.Info", node.InfoArguments{}, &reply); err != nil { 26 | return nil, err 27 | } 28 | 29 | return reply, nil 30 | } 31 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/owned.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/account" 10 | "github.com/bitmark-inc/bitmarkd/rpc/owner" 11 | ) 12 | 13 | // OwnedData - data for an ownership request 14 | type OwnedData struct { 15 | Owner *account.Account 16 | Start uint64 17 | Count int 18 | } 19 | 20 | // GetOwned - obtain list of owned bitmarks 21 | func (client *Client) GetOwned(ownedConfig *OwnedData) (*owner.BitmarksReply, error) { 22 | 23 | ownedArgs := owner.BitmarksArguments{ 24 | Owner: ownedConfig.Owner, 25 | Start: ownedConfig.Start, 26 | Count: ownedConfig.Count, 27 | } 28 | 29 | client.printJson("Owned Request", ownedArgs) 30 | 31 | reply := &owner.BitmarksReply{} 32 | err := client.client.Call("Owner.Bitmarks", ownedArgs, reply) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | client.printJson("Owned Reply", reply) 38 | 39 | return reply, nil 40 | } 41 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/payment-command.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/bitmark-inc/bitmarkd/currency" 13 | "github.com/bitmark-inc/bitmarkd/transactionrecord" 14 | ) 15 | 16 | // prefix for the payment command 17 | // assumed format is: paymentCommand 'PaymentId' 'address₁,SatoshiAmount₁' … 'addressN,SatoshiAmountN' 18 | const ( 19 | paymentCommandLive = "bitmark-wallet --conf ${XDG_CONFIG_HOME}/bitmark-wallet/live/live-bitmark-wallet.conf %s sendmany --hex-data '%s'" 20 | paymentCommandTest = "bitmark-wallet --conf ${XDG_CONFIG_HOME}/bitmark-wallet/test/test-bitmark-wallet.conf %s --testnet sendmany --hex-data '%s'" 21 | ) 22 | 23 | func paymentCommand(testnet bool, curr currency.Currency, payId string, payments transactionrecord.PaymentAlternative) string { 24 | 25 | c := strings.ToLower(curr.String()) 26 | 27 | command := "" 28 | if testnet { 29 | command = fmt.Sprintf(paymentCommandTest, c, payId) 30 | } else { 31 | command = fmt.Sprintf(paymentCommandLive, c, payId) 32 | } 33 | 34 | for _, p := range payments { 35 | command += fmt.Sprintf(" '%s,%d'", p.Address, p.Amount) 36 | } 37 | return command 38 | } 39 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/printjson.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | ) 12 | 13 | func (client *Client) printJson(title string, message interface{}) error { 14 | 15 | if !client.verbose { 16 | return nil 17 | } 18 | 19 | prefix := "" 20 | indent := " " 21 | b, err := json.MarshalIndent(message, prefix, indent) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | if title == "" { 27 | fmt.Fprintf(client.handle, "%s\n", b) 28 | } else { 29 | fmt.Fprintf(client.handle, "%s:\n%s\n", title, b) 30 | } 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/rpccalls_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/setup.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "crypto/tls" 10 | "io" 11 | "net" 12 | "net/rpc" 13 | "net/rpc/jsonrpc" 14 | ) 15 | 16 | // Client - to hold RPC connections streams 17 | type Client struct { 18 | conn net.Conn 19 | client *rpc.Client 20 | testnet bool 21 | verbose bool 22 | handle io.Writer // if verbose is set output items here 23 | } 24 | 25 | // NewClient - create a RPC connection to a bitmarkd 26 | func NewClient(testnet bool, connect string, verbose bool, handle io.Writer) (*Client, error) { 27 | 28 | tlsConfig := &tls.Config{ 29 | InsecureSkipVerify: true, 30 | } 31 | 32 | conn, err := tls.Dial("tcp", connect, tlsConfig) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | r := &Client{ 38 | conn: conn, 39 | client: jsonrpc.NewClient(conn), 40 | testnet: testnet, 41 | verbose: verbose, 42 | handle: handle, 43 | } 44 | return r, nil 45 | } 46 | 47 | // Close - shutdown the bitmarkd connection 48 | func (c *Client) Close() { 49 | c.client.Close() 50 | c.conn.Close() 51 | } 52 | -------------------------------------------------------------------------------- /command/bitmark-cli/rpccalls/status.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package rpccalls 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/merkle" 10 | "github.com/bitmark-inc/bitmarkd/rpc/transaction" 11 | ) 12 | 13 | // TransactionStatusData - request data fro transaction status 14 | type TransactionStatusData struct { 15 | TxId string 16 | } 17 | 18 | // GetTransactionStatus - perform a status request 19 | func (client *Client) GetTransactionStatus(statusConfig *TransactionStatusData) (*transaction.StatusReply, error) { 20 | 21 | var txId merkle.Digest 22 | err := txId.UnmarshalText([]byte(statusConfig.TxId)) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | statusArgs := transaction.Arguments{ 28 | TxId: txId, 29 | } 30 | 31 | client.printJson("Status Request", statusArgs) 32 | 33 | var reply transaction.StatusReply 34 | err = client.client.Call("Transaction.Status", statusArgs, &reply) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | client.printJson("Status Reply", reply) 40 | 41 | return &reply, nil 42 | } 43 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-add.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/bitmark-inc/bitmarkd/fault" 12 | "github.com/urfave/cli" 13 | ) 14 | 15 | func runAdd(c *cli.Context) error { 16 | 17 | m := c.App.Metadata["config"].(*metadata) 18 | 19 | name, err := checkName(c.GlobalString("identity")) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | description, err := checkDescription(c.String("description")) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | // blank or a valid seed 30 | seed := c.String("seed") 31 | newSeed := c.Bool("new") 32 | acc := c.String("account") 33 | 34 | if m.verbose { 35 | fmt.Fprintf(m.e, "identity: %s\n", name) 36 | fmt.Fprintf(m.e, "description: %s\n", description) 37 | fmt.Fprintf(m.e, "seed: %s\n", seed) 38 | fmt.Fprintf(m.e, "account: %s\n", acc) 39 | fmt.Fprintf(m.e, "new: %t\n", newSeed) 40 | } 41 | 42 | if acc == "" { 43 | seed, err = checkSeed(seed, newSeed, m.testnet) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | password := c.GlobalString("password") 49 | if password == "" { 50 | password, err = promptNewPassword() 51 | if err != nil { 52 | return err 53 | } 54 | } 55 | 56 | err = m.config.AddIdentity(name, description, seed, password) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | } else if seed == "" && acc != "" && !newSeed { 62 | err = m.config.AddReceiveOnlyIdentity(name, description, acc) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | } else { 68 | return fault.IncompatibleOptions 69 | } 70 | 71 | // require configuration update 72 | m.save = true 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-balance.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runBalance(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | shareId := c.String("share-id") 21 | 22 | count := c.Int("count") 23 | if count <= 0 { 24 | return fmt.Errorf("invalid count: %d", count) 25 | } 26 | 27 | name, owner, err := checkRecipient(c, "owner", m.config) 28 | if err != nil { 29 | name = c.GlobalString("identity") 30 | if name == "" { 31 | name = m.config.DefaultIdentity 32 | } 33 | owner, err = m.config.Account(name) 34 | if err != nil { 35 | return err 36 | } 37 | } 38 | 39 | if m.verbose { 40 | fmt.Fprintf(m.e, "owner: %s\n", name) 41 | fmt.Fprintf(m.e, "shareId: %s\n", shareId) 42 | fmt.Fprintf(m.e, "count: %d\n", count) 43 | } 44 | 45 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 46 | if err != nil { 47 | return err 48 | } 49 | defer client.Close() 50 | 51 | balanceConfig := &rpccalls.BalanceData{ 52 | Owner: owner, 53 | ShareId: shareId, 54 | Count: count, 55 | } 56 | 57 | response, err := client.GetBalance(balanceConfig) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | printJson(m.w, response) 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-bitmarkdinfo.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "github.com/urfave/cli" 10 | 11 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 12 | ) 13 | 14 | func runBitmarkdInfo(c *cli.Context) error { 15 | 16 | m := c.App.Metadata["config"].(*metadata) 17 | 18 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 19 | if err != nil { 20 | return err 21 | } 22 | defer client.Close() 23 | 24 | response, err := client.GetBitmarkInfoCompat() 25 | if err != nil { 26 | return err 27 | } 28 | response["_connection"] = m.config.Connections[m.connectionOffset] 29 | 30 | printJson(m.w, response) 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-blockdecode.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/base64" 10 | "fmt" 11 | 12 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 13 | "github.com/urfave/cli" 14 | ) 15 | 16 | func runBlockDecode(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | packed := c.String("packed") 21 | if packed == "" { 22 | return fmt.Errorf("empty packed") 23 | } 24 | 25 | p64, err := base64.StdEncoding.DecodeString(packed) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | if m.verbose { 31 | fmt.Fprintf(m.e, "packed: %s\n", packed) 32 | } 33 | 34 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 35 | if err != nil { 36 | return err 37 | } 38 | defer client.Close() 39 | 40 | blockDecodeConfig := &rpccalls.BlockDecodeData{ 41 | Packed: p64, 42 | } 43 | 44 | response, err := client.DecodeBlock(blockDecodeConfig) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | printJson(m.w, response) 50 | 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-blockdump.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 12 | "github.com/urfave/cli" 13 | ) 14 | 15 | func runBlockDump(c *cli.Context) error { 16 | 17 | m := c.App.Metadata["config"].(*metadata) 18 | 19 | block := c.Uint64("start") 20 | if block < 1 { 21 | return fmt.Errorf("invalid start block: %d", block) 22 | } 23 | 24 | count := c.Int("count") 25 | if count <= 0 { 26 | return fmt.Errorf("invalid count: %d", count) 27 | } 28 | 29 | txs := c.Bool("txs") 30 | if m.verbose { 31 | fmt.Fprintf(m.e, "start block: %d\n", block) 32 | fmt.Fprintf(m.e, "count: %d\n", count) 33 | fmt.Fprintf(m.e, "decode txs: %t\n", txs) 34 | } 35 | 36 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 37 | if err != nil { 38 | return err 39 | } 40 | defer client.Close() 41 | 42 | blockDumpConfig := &rpccalls.BlockDumpData{ 43 | Block: block, 44 | Count: count, 45 | Txs: txs, 46 | } 47 | 48 | response, err := client.GetBlocks(blockDumpConfig) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | printJson(m.w, response) 54 | 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-blocktransfer.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | "github.com/bitmark-inc/bitmarkd/currency" 15 | ) 16 | 17 | func runBlockTransfer(c *cli.Context) error { 18 | 19 | m := c.App.Metadata["config"].(*metadata) 20 | 21 | txId, err := checkTxId(c.String("txid")) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | to, newOwner, err := checkRecipient(c, "receiver", m.config) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | bitcoinAddress, err := checkCoinAddress(currency.Bitcoin, c.String("bitcoin"), m.testnet) 32 | if err != nil { 33 | return err 34 | } 35 | litecoinAddress, err := checkCoinAddress(currency.Litecoin, c.String("litecoin"), m.testnet) 36 | if err != nil { 37 | return err 38 | } 39 | 40 | from, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | payments := currency.Map{ 46 | currency.Bitcoin: bitcoinAddress, 47 | currency.Litecoin: litecoinAddress, 48 | } 49 | 50 | if m.verbose { 51 | fmt.Fprintf(m.e, "txid: %s\n", txId) 52 | fmt.Fprintf(m.e, "receiver: %s\n", to) 53 | fmt.Fprintf(m.e, "sender: %s\n", from) 54 | } 55 | 56 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 57 | if err != nil { 58 | return err 59 | } 60 | defer client.Close() 61 | 62 | transferConfig := &rpccalls.BlockTransferData{ 63 | Owner: owner, 64 | NewOwner: newOwner, 65 | Payments: payments, 66 | TxId: txId, 67 | } 68 | 69 | response, err := client.SingleSignedBlockTransfer(transferConfig) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | printJson(m.w, response) 75 | 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-changepassword.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "github.com/urfave/cli" 10 | ) 11 | 12 | func runChangePassword(c *cli.Context) error { 13 | 14 | m := c.App.Metadata["config"].(*metadata) 15 | 16 | // check existing password 17 | name, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | // prompt new password and confirm 23 | newPassword, err := promptNewPassword() 24 | if err != nil { 25 | return err 26 | } 27 | 28 | err = m.config.AddIdentity(name, owner.Description, owner.Seed, newPassword) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | m.save = true 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-countersign.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runCountersign(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | hex, err := checkTransferTx(c.String("transaction")) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | // this command is run by the receiver so from is used to get 26 | 27 | to, newOwner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | if m.verbose { 33 | fmt.Fprintf(m.e, "tx: %s\n", hex) 34 | fmt.Fprintf(m.e, "receiver: %s\n", to) 35 | } 36 | 37 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 38 | if err != nil { 39 | return err 40 | } 41 | defer client.Close() 42 | 43 | countersignConfig := &rpccalls.CountersignData{ 44 | Transaction: hex, 45 | NewOwner: newOwner, 46 | } 47 | 48 | response, err := client.Countersign(countersignConfig) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | printJson(m.w, response) 54 | 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-fingerprint.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "io/ioutil" 11 | "os" 12 | 13 | "github.com/urfave/cli" 14 | "golang.org/x/crypto/sha3" 15 | ) 16 | 17 | // version byte prefix for fingerprint file 18 | const ( 19 | fingerprintVersion byte = 0x01 20 | ) 21 | 22 | func runFingerprint(c *cli.Context) error { 23 | 24 | m := c.App.Metadata["config"].(*metadata) 25 | 26 | fileName, err := checkFileName(c.String("file")) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | if m.verbose { 32 | fmt.Fprintf(m.e, "checksumming file: %s\n", fileName) 33 | } 34 | 35 | file, err := os.Open(fileName) 36 | if err != nil { 37 | return err 38 | } 39 | 40 | data, err := ioutil.ReadAll(file) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | fingerprint := sha3.Sum512(data) 46 | strFP := fmt.Sprintf("%02x%x", fingerprintVersion, fingerprint) 47 | 48 | if m.verbose { 49 | fmt.Fprintf(m.e, "fingerprint: %s\n", strFP) 50 | } else { 51 | out := struct { 52 | FileName string `json:"file_name"` 53 | Fingerprint string `json:"fingerprint"` 54 | }{ 55 | FileName: fileName, 56 | Fingerprint: strFP, 57 | } 58 | printJson(m.w, out) 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-fullprovenance.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2021 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 12 | "github.com/urfave/cli" 13 | ) 14 | 15 | func runFullProvenance(c *cli.Context) error { 16 | 17 | m := c.App.Metadata["config"].(*metadata) 18 | 19 | bitmarkId, err := checkTxId(c.String("bitmarkid")) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | if m.verbose { 25 | fmt.Fprintf(m.e, "bitmark id: %s\n", bitmarkId) 26 | } 27 | 28 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 29 | if err != nil { 30 | return err 31 | } 32 | defer client.Close() 33 | 34 | // map for adding identity name to full provenance records 35 | ids := make(map[string]string) 36 | for name, id := range m.config.Identities { 37 | ids[id.Account] = name 38 | } 39 | 40 | fullProvenanceConfig := &rpccalls.FullProvenanceData{ 41 | BitmarkId: bitmarkId, 42 | Identities: ids, 43 | } 44 | 45 | response, err := client.GetFullProvenance(fullProvenanceConfig) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | printJson(m.w, response) 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-grant.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runGrant(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | to, recipient, err := checkRecipient(c, "receiver", m.config) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | shareId, err := checkTxId(c.String("share-id")) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | quantity := c.Uint64("quantity") 31 | if quantity == 0 { 32 | return fmt.Errorf("invalid quantity: %d", quantity) 33 | } 34 | 35 | beforeBlock := c.Uint64("before-block") 36 | 37 | from, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if m.verbose { 43 | fmt.Fprintf(m.e, "shareId: %s\n", shareId) 44 | fmt.Fprintf(m.e, "quantity: %d\n", quantity) 45 | fmt.Fprintf(m.e, "sender: %s\n", from) 46 | fmt.Fprintf(m.e, "receiver: %s\n", to) 47 | fmt.Fprintf(m.e, "beforeBlock: %d\n", beforeBlock) 48 | } 49 | 50 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 51 | if err != nil { 52 | return err 53 | } 54 | defer client.Close() 55 | 56 | grantConfig := &rpccalls.GrantData{ 57 | ShareId: shareId, 58 | Quantity: quantity, 59 | Owner: owner, 60 | Recipient: recipient, 61 | BeforeBlock: beforeBlock, 62 | } 63 | 64 | response, err := client.Grant(grantConfig) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | printJson(m.w, response) 70 | 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-list.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "io" 11 | "sort" 12 | 13 | "github.com/urfave/cli" 14 | ) 15 | 16 | func runList(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | if c.Bool("connections") { 21 | return listConnections(m.w, m.config.Connections, c.Bool("json")) 22 | } 23 | 24 | // normal list identities 25 | identities := m.config.Identities 26 | 27 | names := make([]string, len(identities)) 28 | i := 0 29 | for name := range identities { 30 | names[i] = name 31 | i += 1 32 | } 33 | sort.Strings(names) 34 | 35 | if c.Bool("json") { 36 | type item struct { 37 | HasSecret bool `json:"hasSecretKey"` 38 | Name string `json:"name"` 39 | Account string `json:"account"` 40 | Description string `json:"description"` 41 | } 42 | jsonData := make([]item, len(names)) 43 | 44 | for i, name := range names { 45 | jsonData[i].HasSecret = identities[name].Salt != "" 46 | jsonData[i].Name = name 47 | jsonData[i].Account = identities[name].Account 48 | jsonData[i].Description = identities[name].Description 49 | } 50 | 51 | printJson(m.w, jsonData) 52 | 53 | } else { 54 | for _, name := range names { 55 | flag := "--" 56 | if identities[name].Salt != "" { 57 | flag = "SK" 58 | } 59 | fmt.Fprintf(m.w, "%s %-20s %s %q\n", flag, name, identities[name].Account, identities[name].Description) 60 | } 61 | } 62 | 63 | return nil 64 | } 65 | 66 | func listConnections(handle io.Writer, connections []string, printJSON bool) error { 67 | if printJSON { 68 | printJson(handle, connections) 69 | } else { 70 | for i, conn := range connections { 71 | fmt.Fprintf(handle, "%4d %s\n", i, conn) 72 | } 73 | } 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-owned.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runOwned(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | ownerId := c.String("owner") 21 | if ownerId == "" { 22 | ownerId = c.GlobalString("identity") 23 | if ownerId == "" { 24 | ownerId = m.config.DefaultIdentity 25 | } 26 | } 27 | 28 | start := c.Uint64("start") 29 | 30 | count := c.Int("count") 31 | if count <= 0 { 32 | return fmt.Errorf("invalid count: %d", count) 33 | } 34 | 35 | if m.verbose { 36 | fmt.Fprintf(m.e, "owner: %s\n", ownerId) 37 | fmt.Fprintf(m.e, "start: %d\n", start) 38 | fmt.Fprintf(m.e, "count: %d\n", count) 39 | } 40 | 41 | owner, err := m.config.Account(ownerId) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 47 | if err != nil { 48 | return err 49 | } 50 | defer client.Close() 51 | 52 | ownedConfig := &rpccalls.OwnedData{ 53 | Owner: owner, 54 | Start: start, 55 | Count: count, 56 | } 57 | 58 | response, err := client.GetOwned(ownedConfig) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | printJson(m.w, response) 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-provenance.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runProvenance(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | txId, err := checkTxId(c.String("txid")) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | count := c.Int("count") 26 | if count <= 0 { 27 | return fmt.Errorf("invalid count: %d", count) 28 | } 29 | 30 | if m.verbose { 31 | fmt.Fprintf(m.e, "txid: %s\n", txId) 32 | fmt.Fprintf(m.e, "count: %d\n", count) 33 | } 34 | 35 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 36 | if err != nil { 37 | return err 38 | } 39 | defer client.Close() 40 | 41 | // map for adding identity name to provenance records 42 | ids := make(map[string]string) 43 | for name, id := range m.config.Identities { 44 | ids[id.Account] = name 45 | } 46 | 47 | provenanceConfig := &rpccalls.ProvenanceData{ 48 | TxId: txId, 49 | Count: count, 50 | Identities: ids, 51 | } 52 | 53 | response, err := client.GetProvenance(provenanceConfig) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | printJson(m.w, response) 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-seed.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/urfave/cli" 13 | 14 | "github.com/bitmark-inc/bitmarkd/account" 15 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/configuration" 16 | ) 17 | 18 | // merge the account string to private data 19 | type seedResult struct { 20 | *configuration.Private 21 | Name string `json:"name"` 22 | Account string `json:"account"` 23 | Phrase string `json:"recovery_phrase"` 24 | } 25 | 26 | // to decrypt and show the secret data 27 | func runSeed(c *cli.Context) error { 28 | 29 | m := c.App.Metadata["config"].(*metadata) 30 | 31 | name, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | phrase, err := account.Base58EncodedSeedToPhrase(owner.Seed) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | if c.Bool("recovery") { 42 | fmt.Printf("recovery phrase:\n%s", prettyPhrase(phrase)) 43 | return nil 44 | } 45 | 46 | result := seedResult{ 47 | Private: owner, 48 | Name: name, 49 | Account: owner.PrivateKey.Account().String(), 50 | Phrase: strings.Join(phrase, " "), 51 | } 52 | 53 | printJson(m.w, result) 54 | return nil 55 | } 56 | 57 | // convert slice of string phrase to pretty string format 58 | func prettyPhrase(phrase []string) string { 59 | var builder strings.Builder 60 | 61 | for i, p := range phrase { 62 | builder.WriteString(p) 63 | breakline := (i+1)%6 == 0 64 | if breakline { 65 | builder.WriteString("\n") 66 | } else if i < len(phrase)-1 { 67 | builder.WriteString(" ") 68 | } 69 | } 70 | 71 | return builder.String() 72 | } 73 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-share.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runShare(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | txId, err := checkTxId(c.String("txid")) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | quantity := c.Int("quantity") 26 | if quantity <= 0 { 27 | return fmt.Errorf("invalid quantity: %d", quantity) 28 | } 29 | 30 | from, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | if m.verbose { 36 | fmt.Fprintf(m.e, "from: %s\n", from) 37 | fmt.Fprintf(m.e, "txid: %s\n", txId) 38 | fmt.Fprintf(m.e, "quantity: %d\n", quantity) 39 | } 40 | 41 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 42 | if err != nil { 43 | return err 44 | } 45 | defer client.Close() 46 | 47 | // make Share 48 | shareConfig := &rpccalls.ShareData{ 49 | Owner: owner, 50 | TxId: txId, 51 | Quantity: uint64(quantity), 52 | } 53 | 54 | response, err := client.Share(shareConfig) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | printJson(m.w, response) 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-transactionstatus.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runTransactionStatus(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | txId, err := checkTxId(c.String("txid")) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | if m.verbose { 26 | fmt.Fprintf(m.e, "txid: %s\n", txId) 27 | } 28 | 29 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 30 | if err != nil { 31 | return err 32 | } 33 | defer client.Close() 34 | 35 | statusConfig := &rpccalls.TransactionStatusData{ 36 | TxId: txId, 37 | } 38 | 39 | response, err := client.GetTransactionStatus(statusConfig) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | printJson(m.w, response) 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /command/bitmark-cli/run-transfer.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/urfave/cli" 12 | 13 | "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/rpccalls" 14 | ) 15 | 16 | func runTransfer(c *cli.Context) error { 17 | 18 | m := c.App.Metadata["config"].(*metadata) 19 | 20 | txId, err := checkTxId(c.String("txid")) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | to, recipient, err := checkRecipient(c, "receiver", m.config) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | from, owner, err := checkOwnerWithPasswordPrompt(c.GlobalString("identity"), m.config, c) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | if m.verbose { 36 | fmt.Fprintf(m.e, "txid: %s\n", txId) 37 | fmt.Fprintf(m.e, "receiver: %s\n", to) 38 | fmt.Fprintf(m.e, "sender: %s\n", from) 39 | } 40 | 41 | client, err := rpccalls.NewClient(m.testnet, m.config.Connections[m.connectionOffset], m.verbose, m.e) 42 | if err != nil { 43 | return err 44 | } 45 | defer client.Close() 46 | 47 | transferConfig := &rpccalls.TransferData{ 48 | Owner: owner, 49 | NewOwner: recipient, 50 | TxId: txId, 51 | } 52 | 53 | if c.Bool("unratified") { 54 | 55 | response, err := client.Transfer(transferConfig) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | printJson(m.w, response) 61 | 62 | } else { 63 | response, err := client.SingleSignedTransfer(transferConfig) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | printJson(m.w, response) 69 | } 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /command/bitmark-dumpdb/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Bitmark bitmark-dumpdb 7 | package main 8 | -------------------------------------------------------------------------------- /command/bitmark-dumpdb/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | -------------------------------------------------------------------------------- /command/bitmark-info/README.md: -------------------------------------------------------------------------------- 1 | # Bitmarkd Info 2 | 3 | This is a rpc client of bitmarkd in go. 4 | 5 | ## Usage 6 | 7 | Use `bitmark-info -h` to show basic usage of the command 8 | 9 | ``` 10 | $ bitmark-info -h 11 | usage: bitmark-info [--help] [--info-type=TYPE] [host:port] 12 | ``` 13 | 14 | For querying node info, use 15 | 16 | ``` 17 | $ bitmark-info [ip address]:[port] 18 | ``` 19 | 20 | Also, you can select which kind of information you want to query. The 21 | folllowing types are options of information types (TYPE): 22 | 23 | 1. node (node info, the default value) 24 | 2. sbsc (subscriber) 25 | 3. conn (connector) 26 | 27 | For example, 28 | 29 | ``` 30 | $ bitmark-info --info-type=sbsc 127.0.0.1:2130 31 | ``` 32 | 33 | It will then shows the connection of subscriber for a bitmarkd. 34 | -------------------------------------------------------------------------------- /command/bitmark-info/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Bitmark bitmark-info 7 | package main 8 | -------------------------------------------------------------------------------- /command/bitmark-info/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | -------------------------------------------------------------------------------- /command/bitmarkd/certificates.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "io/ioutil" 10 | "os" 11 | "time" 12 | 13 | "golang.org/x/crypto/sha3" 14 | 15 | "github.com/bitmark-inc/bitmarkd/fault" 16 | "github.com/bitmark-inc/bitmarkd/util" 17 | "github.com/bitmark-inc/certgen" 18 | ) 19 | 20 | // create a self-signed certificate 21 | func makeSelfSignedCertificate(name string, certificateFileName string, privateKeyFileName string, override bool, extraHosts []string) error { 22 | 23 | if util.EnsureFileExists(certificateFileName) { 24 | return fault.CertificateFileAlreadyExists 25 | } 26 | 27 | if util.EnsureFileExists(privateKeyFileName) { 28 | return fault.KeyFileAlreadyExists 29 | } 30 | 31 | org := "bitmarkd self signed cert for: " + name 32 | validUntil := time.Now().Add(10 * 365 * 24 * time.Hour) 33 | cert, key, err := certgen.NewTLSCertPair(org, validUntil, override, extraHosts) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | if err := ioutil.WriteFile(certificateFileName, cert, 0o666); err != nil { 39 | return err 40 | } 41 | 42 | if err = ioutil.WriteFile(privateKeyFileName, key, 0o600); err != nil { 43 | os.Remove(certificateFileName) 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | 50 | // CertificateFingerprint - compute the fingerprint of a certificate 51 | // 52 | // FreeBSD: openssl x509 -outform DER -in bitmarkd-local-rpc.crt | sha3sum -a 256 53 | // Darwin: openssl x509 -outform DER -in bitmarkd-local-rpc.crt | sha3-256sum 54 | func CertificateFingerprint(certificate []byte) [32]byte { 55 | return sha3.Sum256(certificate) 56 | } 57 | -------------------------------------------------------------------------------- /command/bitmarkd/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // bitmarkd main program 7 | package main 8 | -------------------------------------------------------------------------------- /command/bitmarkd/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | -------------------------------------------------------------------------------- /command/bitmarkd/stats.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "runtime" 11 | "time" 12 | 13 | "github.com/bitmark-inc/logger" 14 | ) 15 | 16 | const ( 17 | statsDelay = 60 * time.Second 18 | mega = 1048576 19 | ) 20 | 21 | func memstats() { 22 | 23 | log := logger.New("memory") 24 | 25 | for { 26 | var m runtime.MemStats 27 | runtime.ReadMemStats(&m) 28 | 29 | text, err := json.Marshal(m) 30 | if err != nil { 31 | log.Errorf("marshal error: %s", err) 32 | } else { 33 | log.Infof("stats: %s", text) 34 | } 35 | a := m.Alloc / mega 36 | t := m.TotalAlloc / mega 37 | s := m.Sys / mega 38 | log.Warnf("allocated: %d M cumulative: %d M OS virtual: %d M", a, t, s) 39 | 40 | time.Sleep(statsDelay) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /command/bm-rate/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | // bitmarkd rate test program 11 | package main 12 | -------------------------------------------------------------------------------- /command/bm-rate/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | package main 11 | -------------------------------------------------------------------------------- /command/makegenesis/common_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | package main_test 11 | 12 | import ( 13 | "os" 14 | "testing" 15 | 16 | "github.com/bitmark-inc/bitmarkd/chain" 17 | "github.com/bitmark-inc/bitmarkd/mode" 18 | "github.com/bitmark-inc/logger" 19 | ) 20 | 21 | // remove all files created by test 22 | func removeFiles() { 23 | os.RemoveAll("test.log") 24 | } 25 | 26 | // configure for testing 27 | func setup(t *testing.T, testnet bool) { 28 | removeFiles() 29 | 30 | logger.Initialise(logger.Configuration{ 31 | Directory: ".", 32 | File: "test.log", 33 | Size: 50000, 34 | Count: 10, 35 | }) 36 | 37 | if testnet { 38 | mode.Initialise(chain.Local) 39 | } else { 40 | mode.Initialise(chain.Bitmark) 41 | } 42 | } 43 | 44 | // post test cleanup 45 | func teardown(t *testing.T) { 46 | mode.Finalise() 47 | logger.Finalise() 48 | removeFiles() 49 | } 50 | -------------------------------------------------------------------------------- /command/makegenesis/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | ) 15 | 16 | func main() { 17 | fmt.Printf("makegenesis is a dummy program, just run its tests instead\n") 18 | } 19 | -------------------------------------------------------------------------------- /command/makeproof/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | package main 11 | 12 | import ( 13 | "encoding/binary" 14 | "encoding/hex" 15 | "fmt" 16 | "os" 17 | 18 | "golang.org/x/crypto/sha3" 19 | ) 20 | 21 | func main() { 22 | if len(os.Args) < 3 { 23 | fmt.Printf("usage: makeproof payId payNonce\n") 24 | return 25 | } 26 | 27 | payId := toHex(os.Args[1]) 28 | payNonce := toHex(os.Args[2]) 29 | 30 | nonce := uint64(12345) 31 | nonceBuffer := make([]byte, 8) 32 | 33 | for { 34 | nonce += 113113 35 | binary.BigEndian.PutUint64(nonceBuffer, nonce) 36 | 37 | // compute hash 38 | h := sha3.New256() 39 | h.Write(payId) 40 | h.Write(payNonce) 41 | h.Write(nonceBuffer) 42 | var digest [32]byte 43 | h.Sum(digest[:0]) 44 | if digest[0]|digest[1]|digest[2] == 0 { 45 | fmt.Printf("possible nonce: %x with digest: %x\n", nonceBuffer, digest) 46 | } 47 | } 48 | } 49 | 50 | func toHex(s string) []byte { 51 | 52 | size := hex.DecodedLen(len(s)) 53 | 54 | buffer := make([]byte, size) 55 | byteCount, err := hex.Decode(buffer, []byte(s)) 56 | if err != nil { 57 | fmt.Printf("hex decode error: %s\n", err) 58 | panic("hex error") 59 | } 60 | if byteCount != size { 61 | panic("hex size mismatch") 62 | } 63 | 64 | return buffer 65 | } 66 | -------------------------------------------------------------------------------- /command/recorderd/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Proof-of-work program for bitmark system 7 | // 8 | // This program subscribes to potential blocks stream on a bitmarkd 9 | // and determines an argon2 hash value that meets the current network 10 | // difficulty value. 11 | package main 12 | -------------------------------------------------------------------------------- /command/recorderd/main_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | -------------------------------------------------------------------------------- /command/simbm/.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | 3 | just-testing/ 4 | *.log 5 | *.conf 6 | -------------------------------------------------------------------------------- /command/simbm/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Copyright (c) 2014-2020 Bitmark Inc. 7 | // Use of this source code is governed by an ISC 8 | // license that can be found in the LICENSE file. 9 | 10 | // bitmark-minerd main program 11 | package main 12 | -------------------------------------------------------------------------------- /command/simbm/simbm.conf.sample: -------------------------------------------------------------------------------- 1 | # simbm.conf -*- mode: libucl -*- 2 | 3 | # "." is a special case - it uses the path from the configuration file 4 | # as the data directory. 5 | # all keys and logs are relative to this directory 6 | # unless the are overridden with absolute paths. 7 | #data_directory = "." 8 | data_directory = "/var/lib/simbm" 9 | 10 | # optional pid file if not absolute path then is created relative to 11 | # the data directory 12 | # pidfile = "simbm.pid" 13 | 14 | # select the chain of the network for peer connections 15 | # cross chain networking connects will not work 16 | #chain = bitmark 17 | #chain = testing 18 | chain = local 19 | 20 | # proofer listening ports 21 | proofer { 22 | 23 | public_key = simbm-local.public 24 | private_key = simbm-local.private 25 | 26 | publish = "127.0.0.1:3749" 27 | submit = "127.0.0.1:3750" 28 | } 29 | 30 | # logging configuration 31 | logging { 32 | size = 1048576 33 | count = 10 34 | 35 | # set the logging level for various modules 36 | # modules not overridden with get the value from "*" 37 | # the default value for "*" is "critical" 38 | levels { 39 | "*" = info 40 | # "*" = debug 41 | 42 | # data 43 | mode = info 44 | 45 | # mining 46 | submit = info 47 | publish = info 48 | 49 | # other 50 | main = info 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /configuration/configuration_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package configuration 7 | -------------------------------------------------------------------------------- /configuration/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package configuration - parse a Lua configuration file 7 | // 8 | // most of base Lua is available such as reading files to set key data 9 | // and getenv to extract environment supplied items. 10 | package configuration 11 | -------------------------------------------------------------------------------- /constants/constants.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package constants 7 | 8 | import ( 9 | "time" 10 | ) 11 | 12 | // the time for a pending record to expire 13 | const ( 14 | ReservoirTimeout = 45 * time.Minute 15 | ) 16 | 17 | // the time for looking back at old payments when starting up 18 | const ( 19 | OldPaymentTime = 5 * 24 * time.Hour 20 | ) 21 | 22 | // the maximum time before unverified asset is expired 23 | const ( 24 | AssetTimeout = 3 * ReservoirTimeout / 2 25 | ) 26 | 27 | // the time between rebroadcasts of unconfirmed transactions 28 | const ( 29 | RebroadcastInterval = 3 * ReservoirTimeout / 4 30 | ) 31 | -------------------------------------------------------------------------------- /constants/constants_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package constants 7 | -------------------------------------------------------------------------------- /constants/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package constants - constants that could be tuned 7 | package constants 8 | -------------------------------------------------------------------------------- /counter/counter.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package counter 7 | 8 | import ( 9 | "sync/atomic" 10 | ) 11 | 12 | // Counter - type to denote a counter that can be synchronously increments or decremented 13 | // just a 64 bit unsigned integer 14 | type Counter uint64 15 | 16 | // Increment - add 1 to a counter, returns new value 17 | func (ic *Counter) Increment() uint64 { 18 | return atomic.AddUint64((*uint64)(ic), 1) 19 | } 20 | 21 | // Decrement - subtract 1 from a counter, returns new value 22 | func (ic *Counter) Decrement() uint64 { 23 | return atomic.AddUint64((*uint64)(ic), ^uint64(0)) 24 | } 25 | 26 | // Uint64 - returns current value 27 | func (ic *Counter) Uint64() uint64 { 28 | return atomic.AddUint64((*uint64)(ic), 0) 29 | } 30 | 31 | // IsZero - check if zero 32 | func (ic *Counter) IsZero() bool { 33 | return atomic.AddUint64((*uint64)(ic), 0) == 0 34 | } 35 | -------------------------------------------------------------------------------- /counter/counter_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package counter_test 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/bitmark-inc/bitmarkd/counter" 12 | ) 13 | 14 | // test incrementing/decrementing a counter 15 | func TestCounter(t *testing.T) { 16 | 17 | var c1 counter.Counter 18 | 19 | if !c1.IsZero() { 20 | t.Errorf("counter is not zero at start: %d", c1.Uint64()) 21 | } 22 | 23 | c1.Increment() 24 | c1.Increment() 25 | c1.Increment() 26 | c1.Increment() 27 | c1.Increment() 28 | 29 | if c1.Uint64() != 5 { 30 | t.Errorf("counter is not 5 after iincrementing: %d", c1.Uint64()) 31 | } 32 | 33 | c1.Decrement() 34 | 35 | if c1.Uint64() != 4 { 36 | t.Errorf("counter is not 5 after iincrementing: %d", c1.Uint64()) 37 | } 38 | 39 | c1.Decrement() 40 | c1.Decrement() 41 | c1.Decrement() 42 | c1.Decrement() 43 | 44 | if !c1.IsZero() { 45 | t.Errorf("counter did not return to zero: %d", c1.Uint64()) 46 | } 47 | 48 | c1.Decrement() 49 | 50 | // check against underflow, i.e. twos complement -1 51 | if ^uint64(0) != c1.Uint64() { 52 | t.Errorf("counter did not underflow: %d", c1.Uint64()) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /counter/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package counter - thread safe counter 7 | package counter 8 | -------------------------------------------------------------------------------- /currency/bitcoin/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package bitcoin - to validate bitcoin addresses 7 | package bitcoin 8 | -------------------------------------------------------------------------------- /currency/bitcoin/validate.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package bitcoin 7 | 8 | import ( 9 | "bytes" 10 | "crypto/sha256" 11 | 12 | "github.com/bitmark-inc/bitmarkd/fault" 13 | "github.com/bitmark-inc/bitmarkd/util" 14 | ) 15 | 16 | // Version - to hold the type of the address 17 | type Version byte 18 | 19 | // AddressBytes - to hold the fixed-length address bytes 20 | type AddressBytes [20]byte 21 | 22 | // from: https://en.bitcoin.it/wiki/List_of_address_prefixes 23 | const ( 24 | Livenet Version = 0 25 | LivenetScript Version = 5 26 | Testnet Version = 111 27 | TestnetScript Version = 196 28 | vNull Version = 0xff 29 | ) 30 | 31 | // ValidateAddress - check the address and return its version 32 | func ValidateAddress(address string) (Version, AddressBytes, error) { 33 | 34 | addr := util.FromBase58(address) 35 | addressBytes := AddressBytes{} 36 | 37 | if len(addr) != 25 { 38 | return vNull, addressBytes, fault.InvalidBitcoinAddress 39 | } 40 | 41 | h := sha256.New() 42 | h.Write(addr[:21]) 43 | d := h.Sum([]byte{}) 44 | h = sha256.New() 45 | h.Write(d) 46 | d = h.Sum([]byte{}) 47 | 48 | if !bytes.Equal(d[0:4], addr[21:]) { 49 | return vNull, addressBytes, fault.InvalidBitcoinAddress 50 | } 51 | 52 | switch Version(addr[0]) { 53 | case Livenet, LivenetScript, Testnet, TestnetScript: 54 | default: 55 | return vNull, addressBytes, fault.InvalidBitcoinAddress 56 | } 57 | 58 | copy(addressBytes[:], addr[1:21]) 59 | 60 | return Version(addr[0]), addressBytes, nil 61 | } 62 | 63 | // IsTestnet - detect if version is a testnet value 64 | func IsTestnet(version Version) bool { 65 | switch version { 66 | case Testnet, TestnetScript: 67 | return true 68 | default: 69 | return false 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /currency/chain_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/bitmark-inc/bitmarkd/chain" 12 | ) 13 | 14 | func TestBtcChainParams(t *testing.T) { 15 | 16 | btcLocalParams := Bitcoin.ChainParam(chain.Local) 17 | 18 | if btcLocalParams.Name != "regtest" { 19 | t.Fatal("invalid network") 20 | } 21 | 22 | if btcLocalParams.HDCoinType != 1 { 23 | t.Fatal("incorrect currency") 24 | } 25 | 26 | btcTestnetParams := Bitcoin.ChainParam(chain.Testing) 27 | 28 | if btcTestnetParams.Name != "testnet3" { 29 | t.Fatal("invalid network") 30 | } 31 | 32 | if btcTestnetParams.HDCoinType != 1 { 33 | t.Fatal("incorrect currency") 34 | } 35 | 36 | btcMainnetParams := Bitcoin.ChainParam(chain.Bitmark) 37 | 38 | if btcMainnetParams.Name != "mainnet" { 39 | t.Fatal("invalid network") 40 | } 41 | 42 | if btcMainnetParams.HDCoinType != 0 { 43 | t.Fatal("incorrect currency") 44 | } 45 | } 46 | 47 | func TestLtcChainParams(t *testing.T) { 48 | 49 | ltcLocalParams := Litecoin.ChainParam(chain.Local) 50 | 51 | if ltcLocalParams.Name != "regtest" { 52 | t.Fatal("invalid network") 53 | } 54 | 55 | if ltcLocalParams.HDCoinType != 1 { 56 | t.Fatal("incorrect currency") 57 | } 58 | 59 | ltcTestnetParams := Litecoin.ChainParam(chain.Testing) 60 | 61 | if ltcTestnetParams.Name != "testnet4" { 62 | t.Fatal("invalid network") 63 | } 64 | 65 | if ltcTestnetParams.HDCoinType != 1 { 66 | t.Fatal("incorrect currency") 67 | } 68 | 69 | ltcMainnetParams := Litecoin.ChainParam(chain.Bitmark) 70 | 71 | if ltcMainnetParams.Name != "mainnet" { 72 | t.Fatal("invalid network") 73 | } 74 | 75 | if ltcMainnetParams.HDCoinType != 2 { 76 | t.Fatal("incorrect currency") 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /currency/conversion.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/fault" 10 | ) 11 | 12 | // Uint64 - convert the currency to a number 13 | func (currency Currency) Uint64() uint64 { 14 | return uint64(currency) 15 | } 16 | 17 | // FromUint64 - convert a number to a currency 18 | func FromUint64(n uint64) (Currency, error) { 19 | if Currency(n) < maximumValue { 20 | return Currency(n), nil 21 | } 22 | return Nothing, fault.InvalidCurrency 23 | } 24 | -------------------------------------------------------------------------------- /currency/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package currency - types and functions for converting currencies to/from enumeration 7 | // values 8 | package currency 9 | -------------------------------------------------------------------------------- /currency/fees.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/fault" 10 | ) 11 | 12 | // GetFee - returns the fee for a specific currency 13 | func (currency Currency) GetFee() (uint64, error) { 14 | switch currency { 15 | case Nothing: 16 | return 0, nil 17 | case Bitcoin: 18 | return 10000, nil 19 | case Litecoin: 20 | return 100000, nil // as of 2017-07-28 Litecoin penalises any Vout < 100,000 Satoshi 21 | default: 22 | return 0, fault.InvalidCurrency 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /currency/litecoin/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package litecoin - to validate litecoin addresses 7 | package litecoin 8 | -------------------------------------------------------------------------------- /currency/litecoin/frombitcoin.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package litecoin 7 | 8 | import ( 9 | "crypto/sha256" 10 | 11 | "github.com/bitmark-inc/bitmarkd/currency/bitcoin" 12 | "github.com/bitmark-inc/bitmarkd/fault" 13 | "github.com/bitmark-inc/bitmarkd/util" 14 | ) 15 | 16 | // FromBitcoin - check the address and return its version 17 | func FromBitcoin(address string) (string, error) { 18 | 19 | version, addressBytes, err := bitcoin.ValidateAddress(address) 20 | 21 | if err != nil { 22 | return "", err 23 | } 24 | 25 | ltcVersion := vNull 26 | 27 | switch version { 28 | case bitcoin.Livenet: 29 | ltcVersion = Livenet 30 | case bitcoin.LivenetScript: 31 | ltcVersion = LivenetScript 32 | // case bitcoin.LivenetScript2: 33 | // ltcVersion = LivenetScript2 34 | case bitcoin.Testnet: 35 | ltcVersion = Testnet 36 | case bitcoin.TestnetScript: 37 | ltcVersion = TestnetScript 38 | default: 39 | return "", fault.InvalidBitcoinAddress 40 | } 41 | 42 | ltc := append([]byte{byte(ltcVersion)}, addressBytes[:]...) 43 | 44 | h := sha256.New() 45 | h.Write(ltc) 46 | d := h.Sum([]byte{}) 47 | h = sha256.New() 48 | h.Write(d) 49 | d = h.Sum([]byte{}) 50 | 51 | ltc = append(ltc, d[0:4]...) 52 | 53 | return util.ToBase58(ltc), nil 54 | } 55 | -------------------------------------------------------------------------------- /currency/litecoin/frombitcoin_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package litecoin_test 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/bitmark-inc/bitmarkd/currency/litecoin" 12 | ) 13 | 14 | // for testing 15 | type convertAddress struct { 16 | btc string 17 | ltc string 18 | testnet bool 19 | } 20 | 21 | func TestConvert(t *testing.T) { 22 | 23 | // from: https://en.bitcoin.it/wiki/List_of_address_prefixes 24 | addresses := []convertAddress{ 25 | { 26 | btc: "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn", 27 | ltc: "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn", 28 | testnet: true, 29 | }, 30 | { 31 | btc: "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc", 32 | ltc: "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc", 33 | testnet: true, 34 | }, 35 | { 36 | btc: "2N1jDsGRZPMATmQYXPH7Q5QeCFqk46eTyDA", 37 | ltc: "2N1jDsGRZPMATmQYXPH7Q5QeCFqk46eTyDA", 38 | testnet: true, 39 | }, 40 | { 41 | btc: "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem", 42 | ltc: "LRiWdjKGSjcwaNpdaPxEgcKQTpQzuT5g6d", 43 | }, 44 | { 45 | btc: "3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX", 46 | ltc: "3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX", 47 | }, 48 | } 49 | 50 | for i, item := range addresses { 51 | actualLtc, err := litecoin.FromBitcoin(item.btc) 52 | if err != nil { 53 | t.Fatalf("%d: error: %s", i, err) 54 | } 55 | if actualLtc != item.ltc { 56 | t.Errorf("%d: actual litecoin: %q expected: %q", i, actualLtc, item.ltc) 57 | } 58 | 59 | ltcVersion, _, err := litecoin.ValidateAddress(actualLtc) 60 | if err != nil { 61 | t.Fatalf("%d: verify error: %s", i, err) 62 | } 63 | 64 | if litecoin.IsTestnet(ltcVersion) { 65 | if !item.testnet { 66 | t.Fatalf("%d: item is not testnet", i) 67 | } 68 | } else { 69 | if item.testnet { 70 | t.Fatalf("%d: item is not livenet", i) 71 | } 72 | } 73 | 74 | t.Logf("%d: btc: %q ltc: %q", i, item.btc, actualLtc) 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /currency/marshalling.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | // MarshalText - convert a currency into JSON 9 | func (currency Currency) MarshalText() ([]byte, error) { 10 | return []byte(currency.String()), nil 11 | } 12 | 13 | // UnmarshalText - convert currency string to a currency enumeration value from JSON 14 | func (currency *Currency) UnmarshalText(s []byte) error { 15 | c, err := fromString(string(s)) 16 | if err != nil { 17 | return err 18 | } 19 | *currency = c 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /currency/satoshi/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package satoshi - to convert satoshi values to integers 7 | package satoshi 8 | -------------------------------------------------------------------------------- /currency/satoshi/satoshi.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package satoshi 7 | 8 | // FromByteString - convert a string to a Satoshi value 9 | // 10 | // i.e. "0.00000001" will convert to uint64(1) 11 | // 12 | // Note: Invalid characters are simply ignored and the conversion 13 | // 14 | // simply stops after 8 decimal places have been processed. 15 | // Extra decimal points will also be ignored. 16 | func FromByteString(btc []byte) uint64 { 17 | 18 | s := uint64(0) 19 | point := false 20 | decimals := 0 21 | 22 | get_digits: 23 | for _, b := range btc { 24 | if b >= '0' && b <= '9' { 25 | s *= 10 26 | s += uint64(b - '0') 27 | if point { 28 | decimals += 1 29 | if decimals >= 8 { 30 | break get_digits 31 | } 32 | } 33 | } else if b == '.' { 34 | point = true 35 | } 36 | } 37 | for decimals < 8 { 38 | s *= 10 39 | decimals += 1 40 | } 41 | 42 | return s 43 | } 44 | -------------------------------------------------------------------------------- /currency/satoshi/satoshi_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package satoshi 7 | 8 | import ( 9 | "testing" 10 | ) 11 | 12 | // check the address conversion to string 13 | func TestStringToSatoshi(t *testing.T) { 14 | tests := []struct { 15 | btc string 16 | satoshi uint64 17 | }{ 18 | {"", 0}, 19 | {"0", 0}, 20 | {"0.0", 0}, 21 | {"0.000000001", 0}, 22 | {"0.00000001", 1}, 23 | {"1", 100000000}, 24 | {"1.0", 100000000}, 25 | {"1.00", 100000000}, 26 | {"1.000", 100000000}, 27 | {"1.0000", 100000000}, 28 | {"1.00000", 100000000}, 29 | {"1.000000", 100000000}, 30 | {"1.0000000", 100000000}, 31 | {"1.00000000", 100000000}, 32 | {"1.10000000", 110000000}, 33 | {"1.1000000", 110000000}, 34 | {"1.100000", 110000000}, 35 | {"1.10000", 110000000}, 36 | {"1.1000", 110000000}, 37 | {"1.100", 110000000}, 38 | {"1.10", 110000000}, 39 | {"1.1", 110000000}, 40 | {"1.01", 101000000}, 41 | {"1.001", 100100000}, 42 | {"1.0001", 100010000}, 43 | {"1.00001", 100001000}, 44 | {"1.000001", 100000100}, 45 | {"1.0000001", 100000010}, 46 | {"1.00000001", 100000001}, 47 | {"1.99999999", 199999999}, 48 | {"9.99999999", 999999999}, 49 | {"99999999.99999998", 9999999999999998}, 50 | {"99999999.99999999", 9999999999999999}, 51 | } 52 | 53 | for i, item := range tests { 54 | s := FromByteString([]byte(item.btc)) 55 | if item.satoshi != s { 56 | t.Errorf("%d: BTC: %q → %d expected: %d", i, item.btc, s, item.satoshi) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /currency/set.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | // Set - currency set 9 | type Set struct { 10 | count int 11 | bits uint64 12 | } 13 | 14 | // MakeSet - create a set of currencies 15 | func MakeSet(currencies ...Currency) Set { 16 | s := Set{} 17 | for _, c := range currencies { 18 | s.Add(c) 19 | } 20 | return s 21 | } 22 | 23 | // Count - returns number of currencies in the set 24 | func (set *Set) Count() int { 25 | return set.count 26 | } 27 | 28 | // Add - returns true if already present 29 | func (set *Set) Add(c Currency) bool { 30 | n := uint64(1) << c 31 | if uint64(0) != n&set.bits { 32 | return true 33 | } 34 | set.count += 1 35 | set.bits |= n 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /currency/validate.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package currency 7 | 8 | import ( 9 | "unicode/utf8" 10 | 11 | "github.com/bitmark-inc/bitmarkd/currency/bitcoin" 12 | "github.com/bitmark-inc/bitmarkd/currency/litecoin" 13 | "github.com/bitmark-inc/bitmarkd/fault" 14 | "github.com/bitmark-inc/logger" 15 | ) 16 | 17 | const ( 18 | maxPaymentAddressLength = 64 19 | ) 20 | 21 | // ValidateAddress - generic validate function 22 | func (currency Currency) ValidateAddress(address string, testnet bool) error { 23 | if utf8.RuneCountInString(address) > maxPaymentAddressLength { 24 | return fault.PaymentAddressTooLong 25 | } 26 | 27 | switch currency { 28 | 29 | case Nothing: 30 | return nil // for genesis blocks 31 | 32 | case Bitcoin: 33 | version, _, err := bitcoin.ValidateAddress(address) 34 | if err != nil { 35 | return err 36 | } 37 | if bitcoin.IsTestnet(version) != testnet { 38 | return fault.BitcoinAddressForWrongNetwork 39 | } 40 | return nil 41 | 42 | case Litecoin: 43 | version, _, err := litecoin.ValidateAddress(address) 44 | if err != nil { 45 | return err 46 | } 47 | if litecoin.IsTestnet(version) != testnet { 48 | return fault.LitecoinAddressForWrongNetwork 49 | } 50 | return nil 51 | 52 | default: 53 | logger.Panicf("missing validation routine for currency: %s", currency) 54 | } 55 | return fault.InvalidCurrency 56 | } 57 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | changelog.old 2 | -------------------------------------------------------------------------------- /debian/README.debian: -------------------------------------------------------------------------------- 1 | Bitmarkd Daemon Debian package 2 | -------------------------------------------------------------------------------- /debian/bitmark-cli.install: -------------------------------------------------------------------------------- 1 | bin/bitmark-cli usr/bin 2 | -------------------------------------------------------------------------------- /debian/bitmark-info.install: -------------------------------------------------------------------------------- 1 | bin/bitmark-info usr/bin 2 | -------------------------------------------------------------------------------- /debian/bitmarkd.install: -------------------------------------------------------------------------------- 1 | etc/bitmarkd.conf.sample etc 2 | etc/bitmarkd.conf.sub etc 3 | bin/bitmarkd usr/sbin 4 | -------------------------------------------------------------------------------- /debian/bitmarkd.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `configure' 4 | # * `abort-upgrade' 5 | # * `abort-remove' `in-favour' 6 | # 7 | # * `abort-remove' 8 | # * `abort-deconfigure' `in-favour' 9 | # `removing' 10 | # 11 | # for details, see http://www.debian.org/doc/debian-policy/ or 12 | # the debian-policy package 13 | 14 | set -e 15 | 16 | case "$1" in 17 | (configure) 18 | # create group 19 | id -g bitmarkd > /dev/null 2>&1 || addgroup --system bitmarkd 20 | # create user 21 | id bitmarkd > /dev/null 2>&1 || \ 22 | adduser --system --home /var/lib/bitmarkd \ 23 | --disabled-password \ 24 | --gecos "Bitmark Daemon" \ 25 | --ingroup bitmarkd bitmarkd 26 | 27 | conf="/etc/bitmarkd.conf.sample" 28 | chown root:bitmarkd "${conf}" 29 | chmod 640 "${conf}" 30 | 31 | [ ! -f /var/lib/bitmarkd/peer.public ] && bitmarkd --config-file /etc/bitmarkd.conf.sample gen-peer-identity /var/lib/bitmarkd/ 32 | [ ! -f /var/lib/bitmarkd/rpc.crt ] && bitmarkd --config-file /etc/bitmarkd.conf.sample gen-rpc-cert /var/lib/bitmarkd/ 33 | [ ! -f /var/lib/bitmarkd/proof.public ] && bitmarkd --config-file /etc/bitmarkd.conf.sample gen-proof-identity /var/lib/bitmarkd/ 34 | chown bitmarkd:bitmarkd -R /var/lib/bitmarkd 35 | 36 | # enable the unit, but don't start it 37 | [ -x /bin/systemctl ] && systemctl enable bitmarkd.service >/dev/null 2>&1 || true 38 | ;; 39 | 40 | (abort-upgrade|abort-remove|abort-deconfigure) 41 | ;; 42 | 43 | (*) 44 | echo "postinst called with unknown argument \`$1'" >&2 45 | exit 1 46 | ;; 47 | esac 48 | 49 | exit 0 50 | -------------------------------------------------------------------------------- /debian/bitmarkd.postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * postrm remove 4 | # * postrm purge 5 | # * upgrade new-version 6 | # * disappear overwriter overwriter-version 7 | # * failed-upgrade old-version 8 | # * abort-install 9 | # * abort-install old-version 10 | # * abort-upgrade old-version 11 | # for details, see http://www.debian.org/doc/debian-policy/ or 12 | # the debian-policy package 13 | 14 | set -e 15 | 16 | # systemd: reload the daemon 17 | [ -x /bin/systemctl ] && systemctl daemon-reload >/dev/null 2>&1 || true 18 | 19 | case "$1" in 20 | (upgrade) 21 | # systemd: start the new version of nginx 22 | [ -d /run/systemd/system ] && systemctl --system daemon-reload >/dev/null || true 23 | [ -x /bin/systemctl ] && systemctl restart bitmarkd.service 24 | ;; 25 | 26 | (purge) 27 | [ -x /bin/systemctl ] && systemctl stop bitmarkd.service >/dev/null 2>&1 || true 28 | # By debian Policy §6.5, we may only rely on essential packages and 29 | # must fail gracefully if they are unavailable. 30 | # Use userdel/groupdel from passwd instead of deluser/delgroup from 31 | # the adduser package. This is because adduser depends on passwd, 32 | # but is of lesser priority. 33 | # Note that at the time of this writing, neither passwd nor adduser 34 | # are essential packages. 35 | userdel bitmarkd >/dev/null 2>&1 || true 36 | groupdel bitmarkd >/dev/null 2>&1 || true 37 | rm -rf /var/lib/bitmarkd /etc/bitmarkd.conf 38 | ;; 39 | 40 | (remove|failed-upgrade|abort-install|abort-upgrade|disappear) 41 | [ -x /bin/systemctl ] && systemctl stop bitmarkd.service >/dev/null 2>&1 || true 42 | ;; 43 | 44 | (*) 45 | echo "postrm called with unknown argument \`$1'" >&2 46 | exit 1 47 | ;; 48 | esac 49 | 50 | [ -d /run/systemd/system ] && systemctl --system daemon-reload >/dev/null || true 51 | 52 | exit 0 53 | -------------------------------------------------------------------------------- /debian/bitmarkd.preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `install' 4 | # * `install' 5 | # * `upgrade' 6 | # * `abort-upgrade' 7 | # for details, see http://www.debian.org/doc/debian-policy/ or 8 | # the debian-policy package 9 | 10 | set -e 11 | 12 | case "$1" in 13 | (install) 14 | # fresh install - remove any old logs 15 | rm -f /var/lib/bitmarkd/log/* 16 | ;; 17 | 18 | (upgrade) 19 | # stop? systemctl stop bitmarkd 20 | ;; 21 | 22 | (abort-upgrade) 23 | ;; 24 | 25 | *) 26 | echo "preinst called with unknown argument \`$1'" >&2 27 | exit 1 28 | ;; 29 | esac 30 | 31 | exit 0 32 | -------------------------------------------------------------------------------- /debian/bitmarkd.prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `install' 4 | # * `install' 5 | # * `upgrade' 6 | # * `abort-upgrade' 7 | # for details, see http://www.debian.org/doc/debian-policy/ or 8 | # the debian-policy package 9 | 10 | set -e 11 | 12 | case "$1" in 13 | (remove|remove-in-favour|deconfigure|deconfigure-in-favour) 14 | systemctl stop bitmarkd >/dev/null 2>&1 || true 15 | ;; 16 | 17 | (upgrade|failed-upgrade) 18 | ;; 19 | 20 | *) 21 | echo "prerm called with unknown argument \`$1'" >&2 22 | exit 1 23 | ;; 24 | esac 25 | 26 | exit 0 27 | -------------------------------------------------------------------------------- /debian/bitmarkd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Bitmark's distributed currency daemon 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Restart=on-failure 8 | 9 | User=bitmarkd 10 | Group=bitmarkd 11 | 12 | PIDFile=/run/bitmarkd.pid 13 | 14 | StandardOutput=journal 15 | StandardError=journal 16 | 17 | WorkingDirectory=/var/lib/bitmarkd 18 | ExecStart=/usr/sbin/bitmarkd --quiet --config-file=/etc/bitmarkd.conf 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2020 Bitmark Inc. 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /debian/dumpdb.install: -------------------------------------------------------------------------------- 1 | bin/bitmark-dumpdb usr/sbin 2 | -------------------------------------------------------------------------------- /debian/recorderd.install: -------------------------------------------------------------------------------- 1 | bin/recorderd usr/sbin 2 | etc/recorderd.conf.sample etc 3 | -------------------------------------------------------------------------------- /debian/recorderd.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `configure' 4 | # * `abort-upgrade' 5 | # * `abort-remove' `in-favour' 6 | # 7 | # * `abort-remove' 8 | # * `abort-deconfigure' `in-favour' 9 | # `removing' 10 | # 11 | # for details, see http://www.debian.org/doc/debian-policy/ or 12 | # the debian-policy package 13 | 14 | set -e 15 | 16 | case "$1" in 17 | (configure) 18 | # create group 19 | id -g recorderd > /dev/null 2>&1 || addgroup --system recorderd 20 | # create user 21 | id recorderd > /dev/null 2>&1 || \ 22 | adduser --system --home /var/lib/recorderd \ 23 | --disabled-password \ 24 | --gecos "Bitmark Recorder" \ 25 | --ingroup recorderd recorderd 26 | 27 | conf="/etc/recorderd.conf" 28 | chown root:recorderd "${conf}" 29 | chmod 640 "${conf}" 30 | # enable the unit, but don't start it 31 | [ -x /bin/systemctl ] && systemctl enable recorderd.service >/dev/null 2>&1 || true 32 | ;; 33 | 34 | (abort-upgrade|abort-remove|abort-deconfigure) 35 | ;; 36 | 37 | (*) 38 | echo "postinst called with unknown argument \`$1'" >&2 39 | exit 1 40 | ;; 41 | esac 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /debian/recorderd.postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * postrm remove 4 | # * postrm purge 5 | # * upgrade new-version 6 | # * disappear overwriter overwriter-version 7 | # * failed-upgrade old-version 8 | # * abort-install 9 | # * abort-install old-version 10 | # * abort-upgrade old-version 11 | # for details, see http://www.debian.org/doc/debian-policy/ or 12 | # the debian-policy package 13 | 14 | set -e 15 | 16 | # systemd: reload the daemon 17 | [ -x /bin/systemctl ] && systemctl daemon-reload >/dev/null 2>&1 || true 18 | 19 | case "$1" in 20 | (upgrade) 21 | # systemd: start the new version of nginx 22 | [ -d /run/systemd/system ] && systemctl --system daemon-reload >/dev/null || true 23 | [ -x /bin/systemctl ] && systemctl restart recorderd.service 24 | ;; 25 | 26 | (purge) 27 | [ -x /bin/systemctl ] && systemctl stop recorderd.service >/dev/null 2>&1 || true 28 | # By debian Policy §6.5, we may only rely on essential packages and 29 | # must fail gracefully if they are unavailable. 30 | # Use userdel/groupdel from passwd instead of deluser/delgroup from 31 | # the adduser package. This is because adduser depends on passwd, 32 | # but is of lesser priority. 33 | # Note that at the time of this writing, neither passwd nor adduser 34 | # are essential packages. 35 | userdel recorderd >/dev/null 2>&1 || true 36 | groupdel recorderd >/dev/null 2>&1 || true 37 | rm -rf /var/lib/recorderd /etc/recorderd.conf 38 | ;; 39 | 40 | (remove|failed-upgrade|abort-install|abort-upgrade|disappear) 41 | [ -x /bin/systemctl ] && systemctl stop recorderd.service >/dev/null 2>&1 || true 42 | ;; 43 | 44 | (*) 45 | echo "postrm called with unknown argument \`$1'" >&2 46 | exit 1 47 | ;; 48 | esac 49 | 50 | [ -d /run/systemd/system ] && systemctl --system daemon-reload >/dev/null || true 51 | 52 | exit 0 53 | -------------------------------------------------------------------------------- /debian/recorderd.preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `install' 4 | # * `install' 5 | # * `upgrade' 6 | # * `abort-upgrade' 7 | # for details, see http://www.debian.org/doc/debian-policy/ or 8 | # the debian-policy package 9 | 10 | set -e 11 | 12 | case "$1" in 13 | (install) 14 | # fresh install - remove any old logs 15 | rm -f /var/lib/recorderd/log/* 16 | ;; 17 | 18 | (upgrade) 19 | # stop? systemctl stop recorderd 20 | ;; 21 | 22 | (abort-upgrade) 23 | ;; 24 | 25 | *) 26 | echo "preinst called with unknown argument \`$1'" >&2 27 | exit 1 28 | ;; 29 | esac 30 | 31 | exit 0 32 | -------------------------------------------------------------------------------- /debian/recorderd.prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # summary of how this script can be called: 3 | # * `install' 4 | # * `install' 5 | # * `upgrade' 6 | # * `abort-upgrade' 7 | # for details, see http://www.debian.org/doc/debian-policy/ or 8 | # the debian-policy package 9 | 10 | set -e 11 | 12 | case "$1" in 13 | (remove|remove-in-favour|deconfigure|deconfigure-in-favour) 14 | systemctl stop recorderd >/dev/null 2>&1 || true 15 | ;; 16 | 17 | (upgrade|failed-upgrade) 18 | ;; 19 | 20 | *) 21 | echo "prerm called with unknown argument \`$1'" >&2 22 | exit 1 23 | ;; 24 | esac 25 | 26 | exit 0 27 | -------------------------------------------------------------------------------- /debian/recorderd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Bitmark's blockchain recorder 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Restart=on-failure 8 | 9 | User=recorderd 10 | Group=recorderd 11 | 12 | PIDFile=/run/recorderd.pid 13 | 14 | StandardOutput=journal 15 | StandardError=journal 16 | 17 | WorkingDirectory=/var/lib/recorderd 18 | ExecStart=/usr/sbin/recorderd --quiet --config-file=/etc/recorderd.conf 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | GOPATH = /tmp/go 5 | GOCACHE = /tmp/.go-cache 6 | BIN_DIR = ${GOPATH}/bin 7 | PROJECT_DIR = ${CURDIR} 8 | COMMAND_DIR = ${PROJECT_DIR}/command 9 | 10 | VERSION := $(shell dpkg-parsechangelog -SVersion | sed 's/-[^-]*$$//') 11 | 12 | override_dh_auto_build: 13 | [ -f "go.tar.gz" ] && tar zxf go.tar.gz -C /tmp 14 | GOPATH="${GOPATH}" GOCACHE="${GOCACHE}" go install -buildmode=exe -ldflags "-X main.version=${VERSION}" ./command/... 15 | 16 | override_dh_auto_install: 17 | # install app binary and configuration files 18 | etc_dir="debian/tmp/etc" ; \ 19 | bin_dir="debian/tmp/bin" ; \ 20 | share_dir="debian/tmp/share" ; \ 21 | mkdir -p "$${etc_dir}" "$${bin_dir}" "$${share_dir}" ; \ 22 | for app in "${COMMAND_DIR}"/* ; \ 23 | do \ 24 | app_base=$$(basename "$${app}") ; \ 25 | conf="${SRC_DIR}/$${app}/$${app_base}.conf.sample" ; \ 26 | [ -f "$${conf}" ] && cp -p "$${conf}" "$${etc_dir}/$${app_base}.conf.sample" || true ; \ 27 | subconf="${SRC_DIR}/$${app}/$${app_base}.conf.sub" ; \ 28 | echo "$${subconf}"; \ 29 | [ -f "$${subconf}" ] && cp -p "$${subconf}" "$${etc_dir}/$${app_base}.conf.sub" || true ; \ 30 | share="${SRC_DIR}/$${app}/share" ; \ 31 | [ -d "$${share}" ] && cp -p "$${share}"/* "$${share_dir}/" || true ; \ 32 | done ; \ 33 | cp -p "${BIN_DIR}"/* "$${bin_dir}/" 34 | 35 | 36 | override_dh_strip: 37 | # Go has lots of problems with stripping 38 | 39 | 40 | override_dh_auto_test: 41 | # no tests 42 | 43 | 44 | override_dh_installinit: 45 | #dh_installinit --name=docker --no-restart-on-upgrade 46 | 47 | 48 | override_dh_auto_clean: 49 | dh_auto_clean 50 | 51 | 52 | # default rules 53 | %: 54 | dh $@ --with=systemd 55 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /difficulty/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package difficulty - implement the difficulty value and its various 7 | // encodings 8 | package difficulty 9 | -------------------------------------------------------------------------------- /doc/release-note-template.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | # How to Upgrade 4 | 5 | If you are running an older version, ... 6 | 7 | # Downgrade warning 8 | 9 | # Notable changes 10 | 11 | ## RPCs 12 | 13 | ## Configuration options 14 | 15 | ## BIP 1: bidirectional connection 16 | 17 | ## Fast synchronization 18 | 19 | 20 | # Low-level changes 21 | 22 | 23 | ## Tests 24 | 25 | 26 | # Change log 27 | -------------------------------------------------------------------------------- /fault/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package fault - error instances 7 | // 8 | // Provides a single instance of errors to allow easy comparison 9 | // without having to resort to partial string matches 10 | package fault 11 | -------------------------------------------------------------------------------- /fault/fault_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package fault 7 | -------------------------------------------------------------------------------- /genesis/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package genesis - live and test genesis blocks 7 | package genesis 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bitmark-inc/bitmarkd 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/bitmark-inc/certgen v0.1.1 7 | github.com/bitmark-inc/exitwithstatus v0.1.2 8 | github.com/bitmark-inc/getoptions v0.1.1 9 | github.com/bitmark-inc/go-argon2 v0.1.5 10 | github.com/bitmark-inc/logger v0.3.7 11 | github.com/btcsuite/btcd v0.24.2 12 | github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 13 | github.com/fsnotify/fsnotify v1.8.0 14 | github.com/golang/mock v1.6.0 15 | github.com/miekg/dns v1.1.62 16 | github.com/patrickmn/go-cache v2.1.0+incompatible 17 | github.com/pebbe/zmq4 v1.2.11 18 | github.com/stretchr/testify v1.9.0 19 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 20 | github.com/urfave/cli v1.22.16 21 | github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 22 | github.com/yuin/gopher-lua v1.1.1 23 | golang.org/x/crypto v0.31.0 24 | golang.org/x/sync v0.10.0 25 | golang.org/x/time v0.8.0 26 | ) 27 | 28 | require ( 29 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect 30 | github.com/btcsuite/btcd/btcutil v1.1.6 // indirect 31 | github.com/btcsuite/btclog v0.0.0-20241017175713-3428138b75c7 // indirect 32 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect 33 | github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect 34 | github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect 35 | github.com/davecgh/go-spew v1.1.1 // indirect 36 | github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect 37 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect 38 | github.com/decred/dcrd/lru v1.1.3 // indirect 39 | github.com/golang/snappy v0.0.4 // indirect 40 | github.com/mitchellh/mapstructure v1.5.0 // indirect 41 | github.com/pmezard/go-difflib v1.0.0 // indirect 42 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 43 | golang.org/x/mod v0.22.0 // indirect 44 | golang.org/x/net v0.33.0 // indirect 45 | golang.org/x/sys v0.28.0 // indirect 46 | golang.org/x/term v0.27.0 // indirect 47 | golang.org/x/tools v0.28.0 // indirect 48 | gopkg.in/yaml.v3 v3.0.1 // indirect 49 | ) 50 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ERROR_CODE=1 4 | SUCCESS_CODE=0 5 | 6 | printf '\nRunning golint...\n' 7 | 8 | # check if program `golint` exist 9 | if [ -z "$(which golint)" ]; then 10 | printf '\nError: golint not found, run: go get github.com/golang/lint/golint\n' 11 | exit $SUCCESS_CODE 12 | fi 13 | 14 | # find modified files 15 | gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$') 16 | 17 | # run golint for each modified file 18 | for gofile in $gofiles 19 | do 20 | lint_result=$(golint $gofile) 21 | err_count=$(echo $lint_result | wc -l | tr -d '[:space:]') 22 | 23 | if [ "$err_count" = "0" ]; then 24 | printf "\n$err_count suggestion(s) for $gofile" 25 | printf "\t$lint_result" 26 | fi 27 | done 28 | 29 | printf '\nFinish code lint...\n' 30 | 31 | # currently, always return success no matter when lint result is 32 | # [ -z "$errors" ] && exit $SUCCESS_CODE 33 | exit $SUCCESS_CODE 34 | -------------------------------------------------------------------------------- /hooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ERROR_CODE=1 4 | SUCCESS_CODE=0 5 | 6 | # text color 7 | RED='\033[0;31m' 8 | NC='\033[0m' 9 | 10 | # make sure environment are set 11 | if [ -z "$GOPATH" ]; then 12 | printf '\nError: environment variable $GOPATH is empty\n' 13 | exit $ERROR_CODE 14 | fi 15 | 16 | # sonarqube (optional) only runs when it's available 17 | # to use on mac, install program by `brew install sonarqube sonar-scanner` 18 | # then start sonarqube on command line by `sonar console` 19 | if [ $(command -v sonar) ] && [ $(command -v sonar-scanner) ]; then 20 | sonar_console_status=$(sonar status | grep 'not running') 21 | if [ -z "$sonar_console_status" ]; then 22 | sonar-scanner 23 | fi 24 | fi 25 | 26 | # go tool vet currently runs without blocking pushing behavior 27 | # show messages to developer to decide take any action or not 28 | printf "\nStart go tool vet (optional to pass)...\n" 29 | vet_flags="-all=true" 30 | go tool vet $vet_flags . 31 | 32 | printf '\n' 33 | 34 | # run tests 35 | printf "\nRunning test cases...\n" 36 | go test $(go list ./... | grep -v /vendor/) 37 | 38 | if [ $? -ne 0 ]; then 39 | printf "\n${RED}Some test cases fail, please try to fix it before keep going...${NC}\n" 40 | exit $ERROR_CODE 41 | fi 42 | 43 | printf "\nFinish running test cases...\n" 44 | 45 | exit $SUCCESS_CODE 46 | -------------------------------------------------------------------------------- /merkle/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package merkle - merkle tree manipulation routines 7 | package merkle 8 | -------------------------------------------------------------------------------- /messagebus/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package messagebus - a queuing system for all message packets 7 | // whether internally generated or received from peers 8 | package messagebus 9 | -------------------------------------------------------------------------------- /mode/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package mode - simple module to record the global running mode 7 | package mode 8 | -------------------------------------------------------------------------------- /mode/mode_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package mode 7 | -------------------------------------------------------------------------------- /ownership/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package ownership - handles low-level access to the ownership data in storage pool 7 | package ownership 8 | -------------------------------------------------------------------------------- /ownership/item.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package ownership 7 | 8 | import ( 9 | "strings" 10 | 11 | "github.com/bitmark-inc/bitmarkd/fault" 12 | "github.com/bitmark-inc/logger" 13 | ) 14 | 15 | // OwnedItem - the flag byte 16 | type OwnedItem byte 17 | 18 | // type codes for flag byte 19 | const ( 20 | OwnedAsset OwnedItem = iota 21 | OwnedBlock OwnedItem = iota 22 | OwnedShare OwnedItem = iota 23 | ) 24 | 25 | // internal conversion 26 | func toString(item OwnedItem) ([]byte, error) { 27 | switch item { 28 | case OwnedAsset: 29 | return []byte("Asset"), nil 30 | case OwnedBlock: 31 | return []byte("Block"), nil 32 | case OwnedShare: 33 | return []byte("Share"), nil 34 | default: 35 | return []byte{}, fault.InvalidItem 36 | } 37 | } 38 | 39 | // String - convert a owned item to its string symbol 40 | func (item OwnedItem) String() string { 41 | s, err := toString(item) 42 | if err != nil { 43 | logger.Panicf("invalid item enumeration: %d", item) 44 | } 45 | return string(s) 46 | } 47 | 48 | // MarshalText - convert item to text 49 | func (item OwnedItem) MarshalText() ([]byte, error) { 50 | s, err := toString(item) 51 | if err != nil { 52 | return nil, err 53 | } 54 | return s, nil 55 | } 56 | 57 | // UnmarshalText - convert test to Item 58 | func (item *OwnedItem) UnmarshalText(s []byte) error { 59 | switch strings.ToLower(string(s)) { 60 | case "asset": 61 | *item = OwnedAsset 62 | case "block": 63 | *item = OwnedBlock 64 | case "share": 65 | *item = OwnedShare 66 | default: 67 | return fault.NotOwnedItem 68 | } 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /ownership/ownership.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package ownership 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/account" 10 | "github.com/bitmark-inc/bitmarkd/storage" 11 | ) 12 | 13 | // Ownership - interface for ownership 14 | type Ownership interface { 15 | ListBitmarksFor(*account.Account, uint64, int) ([]Record, error) 16 | } 17 | 18 | type ownership struct { 19 | PoolOwnerList storage.Handle 20 | PoolOwnerData storage.Handle 21 | } 22 | 23 | func (o ownership) ListBitmarksFor(owner *account.Account, start uint64, count int) ([]Record, error) { 24 | return listBitmarksFor(owner, start, count) 25 | } 26 | 27 | var data ownership 28 | 29 | // Initialise - initialise ownership 30 | func Initialise(ownerList, ownerData storage.Handle) { 31 | data = ownership{ 32 | PoolOwnerList: ownerList, 33 | PoolOwnerData: ownerData, 34 | } 35 | } 36 | 37 | // Get - return Record interface 38 | func Get() Ownership { 39 | return &data 40 | } 41 | -------------------------------------------------------------------------------- /pay/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package pay - miscellaneous type for payment 7 | package pay 8 | -------------------------------------------------------------------------------- /pay/payid.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package pay 7 | 8 | import ( 9 | "encoding/hex" 10 | 11 | "github.com/bitmark-inc/bitmarkd/fault" 12 | "golang.org/x/crypto/sha3" 13 | ) 14 | 15 | // PayId - type to represent a payment identifier 16 | // Note: no reversal is required for this 17 | type PayId [48]byte 18 | 19 | // NewPayId - create a payment identifier from a set of transactions 20 | func NewPayId(packed [][]byte) PayId { 21 | digest := sha3.New384() 22 | for _, data := range packed { 23 | digest.Write(data) 24 | } 25 | hash := digest.Sum([]byte{}) 26 | var payId PayId 27 | copy(payId[:], hash) 28 | return payId 29 | } 30 | 31 | // String - convert a binary pay id to hex string for use by the fmt package (for %s) 32 | func (payid PayId) String() string { 33 | return hex.EncodeToString(payid[:]) 34 | } 35 | 36 | // GoString - convert a binary pay id to hex string for use by the fmt package (for %#v) 37 | func (payid PayId) GoString() string { 38 | return "" 39 | } 40 | 41 | // MarshalText - convert pay id to hex text 42 | func (payid PayId) MarshalText() ([]byte, error) { 43 | size := hex.EncodedLen(len(payid)) 44 | buffer := make([]byte, size) 45 | hex.Encode(buffer, payid[:]) 46 | return buffer, nil 47 | } 48 | 49 | // UnmarshalText - convert hex text into a pay id 50 | func (payid *PayId) UnmarshalText(s []byte) error { 51 | if len(*payid) != hex.DecodedLen(len(s)) { 52 | return fault.NotAPayId 53 | } 54 | byteCount, err := hex.Decode(payid[:], s) 55 | if err != nil { 56 | return err 57 | } 58 | if len(payid) != byteCount { 59 | return fault.NotAPayId 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /pay/payid_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package pay_test 7 | 8 | import ( 9 | "encoding/json" 10 | "testing" 11 | 12 | "github.com/bitmark-inc/bitmarkd/pay" 13 | ) 14 | 15 | func TestPayId(t *testing.T) { 16 | 17 | somedata := [][]byte{ 18 | []byte("abcdefghijklm"), 19 | []byte("nopqrstuvwxyz"), 20 | } 21 | expected := `"fed399d2217aaf4c717ad0c5102c15589e1c990cc2b9a5029056a7f7485888d6ab65db2370077a5cadb53fc9280d278f"` 22 | 23 | payId := pay.NewPayId(somedata) 24 | t.Logf("pay id: %#v", payId) 25 | 26 | buffer, err := json.Marshal(payId) 27 | if err != nil { 28 | t.Fatalf("marshal JSON error: %s", err) 29 | } 30 | 31 | t.Logf("pay id: %s", buffer) 32 | 33 | actual := string(buffer) 34 | if expected != actual { 35 | t.Fatalf("pay id expected: %#v actual: %#v", expected, actual) 36 | } 37 | 38 | var payId2 pay.PayId 39 | err = json.Unmarshal(buffer, &payId2) 40 | if err != nil { 41 | t.Fatalf("unmarshal JSON error: %s", err) 42 | } 43 | 44 | if payId != payId2 { 45 | t.Fatalf("pay id expected: %#v actual: %#v", payId, payId2) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /payment/background.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package payment 7 | 8 | import ( 9 | "sync" 10 | "time" 11 | 12 | "github.com/bitmark-inc/logger" 13 | ) 14 | 15 | const ( 16 | blockchainCheckInterval = 60 * time.Second 17 | ) 18 | 19 | // checker periodically extracts possible txs in the latest block 20 | type checker struct { 21 | log *logger.L 22 | } 23 | 24 | func (c *checker) Run(args interface{}, shutdown <-chan struct{}) { 25 | log := logger.New("checker") 26 | c.log = log 27 | 28 | log.Info("starting…") 29 | loop: 30 | for { 31 | log.Info("begin…") 32 | select { 33 | case <-shutdown: 34 | break loop 35 | 36 | case <-time.After(blockchainCheckInterval): // timeout 37 | log.Info("checking…") 38 | var wg sync.WaitGroup 39 | for _, handler := range globalData.handlers { 40 | wg.Add(1) 41 | go handler.checkLatestBlock(&wg) 42 | } 43 | log.Debug("waiting…") 44 | wg.Wait() 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /payment/common_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package payment 7 | 8 | import ( 9 | "fmt" 10 | "os" 11 | "testing" 12 | 13 | "github.com/bitmark-inc/bitmarkd/mode" 14 | "github.com/bitmark-inc/bitmarkd/storage" 15 | "github.com/bitmark-inc/logger" 16 | ) 17 | 18 | // test database file 19 | const ( 20 | testingDirName = "testing" 21 | databaseFileName = testingDirName + "/test" 22 | ) 23 | 24 | // Test main entrypoint 25 | func TestMain(m *testing.M) { 26 | if err := setup(); err != nil { 27 | os.Exit(1) 28 | } 29 | result := m.Run() 30 | teardown() 31 | os.Exit(result) 32 | } 33 | 34 | // remove all files created by test 35 | func removeFiles() { 36 | os.RemoveAll(testingDirName) 37 | } 38 | 39 | // configure for testing 40 | func setup() error { 41 | removeFiles() 42 | os.Mkdir(testingDirName, 0o700) 43 | 44 | logging := logger.Configuration{ 45 | Directory: testingDirName, 46 | File: "testing.log", 47 | Size: 1048576, 48 | Count: 10, 49 | Console: false, 50 | Levels: map[string]string{ 51 | logger.DefaultTag: "trace", 52 | }, 53 | } 54 | 55 | // start logging 56 | _ = logger.Initialise(logging) 57 | 58 | _ = mode.Initialise("testing") 59 | 60 | // open database 61 | err := storage.Initialise(databaseFileName, false) 62 | if err != nil { 63 | return fmt.Errorf("storage initialise error: %s", err.Error()) 64 | } 65 | 66 | return nil 67 | } 68 | 69 | // post test cleanup 70 | func teardown() { 71 | Finalise() 72 | logger.Finalise() 73 | removeFiles() 74 | } 75 | -------------------------------------------------------------------------------- /payment/currencyhandler.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package payment 7 | 8 | import ( 9 | "sync" 10 | ) 11 | 12 | type currencyHandler interface { 13 | processPastTxs(dat []byte) 14 | processIncomingTx(dat []byte) 15 | checkLatestBlock(wg *sync.WaitGroup) 16 | } 17 | -------------------------------------------------------------------------------- /payment/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package payment - control of payment verification 7 | package payment 8 | -------------------------------------------------------------------------------- /payment/payment_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package payment 7 | -------------------------------------------------------------------------------- /peer/connector_state.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package peer 7 | 8 | // a state type for the thread 9 | type connectorState int 10 | 11 | // state of the connector process 12 | const ( 13 | // register to nodes and make outgoing connections 14 | cStateConnecting connectorState = iota 15 | 16 | // locate node(s) with highest block number 17 | cStateHighestBlock connectorState = iota 18 | 19 | // read block hashes to check for possible fork 20 | cStateForkDetect connectorState = iota 21 | 22 | // fetch blocks from current or fork point 23 | cStateFetchBlocks connectorState = iota 24 | 25 | // rebuild database from fork point (config setting to force total rebuild) 26 | cStateRebuild connectorState = iota 27 | 28 | // signal resync complete and sample nodes to see if out of sync occurs 29 | cStateSampling connectorState = iota 30 | ) 31 | 32 | func (state connectorState) String() string { 33 | switch state { 34 | case cStateConnecting: 35 | return "Connecting" 36 | case cStateHighestBlock: 37 | return "HighestBlock" 38 | case cStateForkDetect: 39 | return "ForkDetect" 40 | case cStateFetchBlocks: 41 | return "FetchBlocks" 42 | case cStateRebuild: 43 | return "Rebuild" 44 | case cStateSampling: 45 | return "Sampling" 46 | default: 47 | return "*Unknown*" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /peer/connector_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package peer 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/golang/mock/gomock" 12 | "github.com/stretchr/testify/assert" 13 | 14 | "github.com/bitmark-inc/bitmarkd/peer/mocks" 15 | ) 16 | 17 | func newTestConnector() *connector { 18 | return &connector{} 19 | } 20 | 21 | func newTestMockUpstream(t *testing.T) (*gomock.Controller, *mocks.MockUpstream) { 22 | ctl := gomock.NewController(t) 23 | return ctl, mocks.NewMockUpstream(ctl) 24 | } 25 | 26 | func TestNextState(t *testing.T) { 27 | c := newTestConnector() 28 | orig := c.state 29 | c.nextState(orig + 1) 30 | assert.Equal(t, orig+1, c.state, "state not increased") 31 | } 32 | 33 | func TestGetConnectedClientCount(t *testing.T) { 34 | c := newTestConnector() 35 | ctl, mockUpstream := newTestMockUpstream(t) 36 | defer ctl.Finish() 37 | 38 | mockUpstream.EXPECT().IsConnected().Return(true).Times(1) 39 | mockUpstream.EXPECT().IsConnected().Return(false).Times(1) 40 | 41 | c.dynamicClients.PushBack(mockUpstream) 42 | actual := c.getConnectedClientCount() 43 | assert.Equal(t, 1, actual, "wrong connected client count") 44 | 45 | actual = c.getConnectedClientCount() 46 | assert.Equal(t, 0, actual, "wrong connected client count") 47 | } 48 | -------------------------------------------------------------------------------- /peer/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package peer - this module handles the peer to peer network 7 | // 8 | // server-side: 9 | // 10 | // * upstream sending of block, transactions 11 | // * listener for RPC requests e.g. retrieve old block 12 | // 13 | // client-side 14 | // 15 | // * connector to retrieve missing data from other listeners 16 | package peer 17 | -------------------------------------------------------------------------------- /peer/mocks/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | list=' 4 | github.com/bitmark-inc/bitmarkd/peer/upstream:Upstream:mock_upstream.go 5 | github.com/bitmark-inc/bitmarkd/zmqutil:Client:mock_zmqutil_client.go 6 | ' 7 | 8 | ERROR() { 9 | printf 'error: ' 10 | printf "$@" 11 | printf '\n' 12 | exit 1 13 | } 14 | 15 | copyright=$(mktemp) 16 | cleanup() { 17 | rm -f "${copyright}" 18 | } 19 | trap cleanup INT EXIT 20 | 21 | 22 | cat < "${copyright}" 23 | SPDX-License-Identifier: ISC 24 | Copyright (c) 2014-2019 Bitmark Inc. 25 | Use of this source code is governed by an ISC 26 | license that can be found in the LICENSE file. 27 | EOF 28 | 29 | 30 | # directory of this script 31 | out=$(dirname "$0") 32 | 33 | # get to project root 34 | while : 35 | do 36 | [ -f go.mod ] && break 37 | cd .. || ERROR 'cannot cd to project root' 38 | [ X"${PWD}" = X"/" ] && ERROR 'cannot cd to project root' 39 | done 40 | 41 | # make the mocks 42 | for item in ${list} 43 | do 44 | src="${item%%:*}" 45 | item="${item#*:}" 46 | names="${item%%:*}" 47 | item="${item#*:}" 48 | dst="${out}/${item%%:*}" 49 | item="${item#*:}" 50 | 51 | printf '%s (%s) → %s\n' "${src}" "${names}" "${dst}" 52 | 53 | mockgen -copyright_file="${copyright}" -package=mocks "${src}" ${names} > "${dst}" 54 | 55 | done 56 | -------------------------------------------------------------------------------- /peer/peer_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package peer 7 | -------------------------------------------------------------------------------- /peer/rpcs.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package peer 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/zmqutil" 10 | ) 11 | 12 | // FetchConnectors - obtain a list of all connector clients 13 | func FetchConnectors() []*zmqutil.Connected { 14 | 15 | globalData.RLock() 16 | 17 | result := make([]*zmqutil.Connected, 0, len(globalData.connectorClients)) 18 | 19 | for _, c := range globalData.connectorClients { 20 | if c != nil { 21 | connect := c.ConnectedTo() 22 | if connect != nil { 23 | result = append(result, connect) 24 | } 25 | } 26 | } 27 | 28 | globalData.RUnlock() 29 | 30 | return result 31 | } 32 | -------------------------------------------------------------------------------- /peer/upstream/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package upstream - maintain REQ/REP connection to clients 7 | // this allow for push of blocks, transactions... 8 | // as well as polling for out of sync conditions 9 | package upstream 10 | -------------------------------------------------------------------------------- /proof/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package proof - prepare blocks for prooferd 7 | package proof 8 | -------------------------------------------------------------------------------- /proof/proof_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package proof_test 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | 13 | "github.com/bitmark-inc/bitmarkd/counter" 14 | "github.com/bitmark-inc/bitmarkd/proof" 15 | ) 16 | 17 | func TestMinedBlocks(t *testing.T) { 18 | assert.Equal(t, counter.Counter(0), proof.MinedBlocks(), "wrong init value") 19 | } 20 | 21 | func TestFailMinedBlocks(t *testing.T) { 22 | assert.Equal(t, counter.Counter(0), proof.FailMinedBlocks(), "wrong init value") 23 | } 24 | -------------------------------------------------------------------------------- /publish/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package publish - this module handles publishing of events for add-on services 7 | // e.g. to maintain a database of transactions 8 | package publish 9 | -------------------------------------------------------------------------------- /publish/publish_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package publish 7 | -------------------------------------------------------------------------------- /reservoir/difficulty.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package reservoir 7 | 8 | import ( 9 | "github.com/bitmark-inc/bitmarkd/difficulty" 10 | "github.com/bitmark-inc/bitmarkd/mode" 11 | ) 12 | 13 | // initial difficulty discount scale 14 | // (this will likely remain fixed, increase initialDifficulty instead) 15 | const ( 16 | onef = 1.00 // 1 item 0% 17 | tenf = 0.95 // 2 .. 10 items -5% 18 | fiftyf = 0.90 // 11 .. 50 items -10% 19 | otherf = 0.85 // 51 ..100 items -15% 20 | ) 21 | 22 | // increase this to make hashing more difficult overall 23 | // (this is then scaled by count*discount) 24 | const ( 25 | //initialDifficulty = 1.0 // 8 leading zero bits 26 | //initialDifficulty = 256.0 // 16 leading zero bits 27 | //initialDifficulty = 65536.0 // 24 leading zero bits 28 | //initialDifficulty = 16777216.0 // 32 leading zero bits 29 | //initialBitmarkDifficulty = 65536.0 // 24 leading zero bits 30 | initialBitmarkDifficulty = 2048.0 // 19 leading zero bits 31 | initialTestingDifficulty = 256.0 // 16 leading zero bits 32 | ) 33 | 34 | // ScaledDifficulty - produce a scaled difficulty based on the number 35 | // of items in a block to be processed and include a quantity discount 36 | func ScaledDifficulty(count int) *difficulty.Difficulty { 37 | 38 | d := difficulty.New() 39 | factor := 1.0 40 | 41 | switch { 42 | case count <= 1: 43 | factor = onef 44 | case count <= 10: 45 | factor = tenf 46 | case count <= 50: 47 | factor = fiftyf 48 | default: 49 | factor = otherf 50 | } 51 | initialDifficulty := initialBitmarkDifficulty 52 | if mode.IsTesting() { 53 | initialDifficulty = initialTestingDifficulty 54 | } 55 | d.Set(float64(count) * initialDifficulty * factor) 56 | return d 57 | } 58 | -------------------------------------------------------------------------------- /reservoir/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package reservoir - storage for: 7 | // 1. pending transactions that are waiting to be verified 8 | // 2. verified transactions that are waiting to be confirmed 9 | package reservoir 10 | -------------------------------------------------------------------------------- /reservoir/expiration.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package reservoir 7 | 8 | import ( 9 | "time" 10 | 11 | "github.com/bitmark-inc/logger" 12 | ) 13 | 14 | const expirationCheckInterval = 5 * time.Minute 15 | 16 | type cleaner struct { 17 | log *logger.L 18 | } 19 | 20 | func (c *cleaner) Run(args interface{}, shutdown <-chan struct{}) { 21 | 22 | c.log = logger.New("expiration") 23 | 24 | ticker := time.NewTicker(expirationCheckInterval) 25 | for { 26 | select { 27 | case <-ticker.C: 28 | c.deleteExpiredItems() 29 | case <-shutdown: 30 | ticker.Stop() 31 | return 32 | } 33 | } 34 | } 35 | 36 | func (c *cleaner) deleteExpiredItems() { 37 | 38 | globalData.Lock() 39 | for key, item := range globalData.pendingTransactions { 40 | if expired(item.expiresAt) { 41 | internalDelete(key) 42 | } 43 | } 44 | for key, item := range globalData.pendingFreeIssues { 45 | if expired(item.expiresAt) { 46 | internalDelete(key) 47 | } 48 | } 49 | for key, item := range globalData.pendingPaidIssues { 50 | if expired(item.expiresAt) { 51 | internalDelete(key) 52 | } 53 | } 54 | globalData.Unlock() 55 | } 56 | 57 | func expired(exp time.Time) bool { 58 | return exp.IsZero() || time.Since(exp) > 0 59 | } 60 | -------------------------------------------------------------------------------- /reservoir/trackingstatus.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package reservoir 7 | 8 | // TrackingStatus - result of track payment/try proof 9 | type TrackingStatus int 10 | 11 | // possible status values 12 | const ( 13 | TrackingNotFound TrackingStatus = iota 14 | TrackingAccepted TrackingStatus = iota 15 | TrackingProcessed TrackingStatus = iota 16 | TrackingInvalid TrackingStatus = iota 17 | ) 18 | 19 | // String - convert the tracking value for printf 20 | func (ts TrackingStatus) String() string { 21 | switch ts { 22 | case TrackingNotFound: 23 | return "NotFound" 24 | case TrackingAccepted: 25 | return "Accepted" 26 | case TrackingProcessed: 27 | return "Processed" 28 | case TrackingInvalid: 29 | return "Invalid" 30 | default: 31 | return "*Unknown*" 32 | } 33 | } 34 | 35 | // MarshalText - convert the tracking value for JSON 36 | func (ts TrackingStatus) MarshalText() ([]byte, error) { 37 | buffer := []byte(ts.String()) 38 | return buffer, nil 39 | } 40 | 41 | // UnmarshalText - convert the tracking value from JSON to enumeration 42 | func (ts *TrackingStatus) UnmarshalText(s []byte) error { 43 | switch string(s) { 44 | case "NotFound": 45 | *ts = TrackingNotFound 46 | case "Accepted": 47 | *ts = TrackingAccepted 48 | case "Processed": 49 | *ts = TrackingProcessed 50 | case "Invalid": 51 | *ts = TrackingInvalid 52 | default: 53 | *ts = TrackingInvalid 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /rpc/certificate/certificate.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package certificate 7 | 8 | import ( 9 | "crypto/tls" 10 | 11 | "golang.org/x/crypto/sha3" 12 | 13 | "github.com/bitmark-inc/logger" 14 | ) 15 | 16 | // Verify that a set of listener parameters are valid 17 | // and return the certificate 18 | func Get(log *logger.L, name, certificate, key string) (*tls.Config, [32]byte, error) { 19 | var fin [32]byte 20 | 21 | keyPair, err := tls.X509KeyPair([]byte(certificate), []byte(key)) 22 | if err != nil { 23 | log.Errorf("%s failed to load keypair: %v", name, err) 24 | return nil, fin, err 25 | } 26 | 27 | tlsConfiguration := &tls.Config{ 28 | Certificates: []tls.Certificate{ 29 | keyPair, 30 | }, 31 | } 32 | 33 | fin = fingerprint(keyPair.Certificate[0]) 34 | 35 | return tlsConfiguration, fin, nil 36 | } 37 | 38 | // fingerprint - compute the fingerprint of a certificate 39 | // 40 | // FreeBSD: openssl x509 -outform DER -in bitmarkd-local-rpc.crt | sha3sum -a 256 41 | func fingerprint(certificate []byte) [32]byte { 42 | return sha3.Sum256(certificate) 43 | } 44 | -------------------------------------------------------------------------------- /rpc/certificate/certificate_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package certificate_test 7 | 8 | import ( 9 | "crypto/tls" 10 | "os" 11 | "path" 12 | "path/filepath" 13 | "testing" 14 | 15 | "github.com/stretchr/testify/assert" 16 | "golang.org/x/crypto/sha3" 17 | 18 | "github.com/bitmark-inc/bitmarkd/rpc/certificate" 19 | "github.com/bitmark-inc/bitmarkd/rpc/fixtures" 20 | "github.com/bitmark-inc/logger" 21 | ) 22 | 23 | func TestGet(t *testing.T) { 24 | fixtures.SetupTestLogger() 25 | defer fixtures.TeardownTestLogger() 26 | 27 | wd, _ := os.Getwd() 28 | fixtureDir := path.Join(filepath.Dir(wd), "fixtures") 29 | cer := fixtures.Certificate(fixtureDir) 30 | key := fixtures.Key(fixtureDir) 31 | 32 | tlsConfig, fingerprint, err := certificate.Get( 33 | logger.New(fixtures.LogCategory), 34 | "test", 35 | cer, 36 | key, 37 | ) 38 | assert.Nil(t, err, "wrong Get") 39 | 40 | pair, _ := tls.X509KeyPair([]byte(cer), []byte(key)) 41 | 42 | assert.Equal(t, sha3.Sum256(pair.Certificate[0]), fingerprint, "wrong fingerprint") 43 | assert.Equal(t, pair, tlsConfig.Certificates[0], "wrong config") 44 | } 45 | -------------------------------------------------------------------------------- /rpc/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package rpc - this is to setup and handle all of the incoming JSON RPC requests 7 | // from clients requiring bitmarkd services 8 | // 9 | // standard golang RPC services can be used on the client side to 10 | // access these services 11 | package rpc 12 | -------------------------------------------------------------------------------- /rpc/listeners/listeners.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package listeners 7 | 8 | type Listener interface { 9 | Serve() error 10 | } 11 | -------------------------------------------------------------------------------- /rpc/mocks/mock_ownership.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Code generated by MockGen. DO NOT EDIT. 7 | // Source: ../ownership/ownership.go 8 | 9 | // Package mocks is a generated GoMock package. 10 | package mocks 11 | 12 | import ( 13 | reflect "reflect" 14 | 15 | gomock "github.com/golang/mock/gomock" 16 | 17 | account "github.com/bitmark-inc/bitmarkd/account" 18 | ownership "github.com/bitmark-inc/bitmarkd/ownership" 19 | ) 20 | 21 | // MockOwnership is a mock of Ownership interface 22 | type MockOwnership struct { 23 | ctrl *gomock.Controller 24 | recorder *MockOwnershipMockRecorder 25 | } 26 | 27 | // MockOwnershipMockRecorder is the mock recorder for MockOwnership 28 | type MockOwnershipMockRecorder struct { 29 | mock *MockOwnership 30 | } 31 | 32 | // NewMockOwnership creates a new mock instance 33 | func NewMockOwnership(ctrl *gomock.Controller) *MockOwnership { 34 | mock := &MockOwnership{ctrl: ctrl} 35 | mock.recorder = &MockOwnershipMockRecorder{mock} 36 | return mock 37 | } 38 | 39 | // EXPECT returns an object that allows the caller to indicate expected use 40 | func (m *MockOwnership) EXPECT() *MockOwnershipMockRecorder { 41 | return m.recorder 42 | } 43 | 44 | // ListBitmarksFor mocks base method 45 | func (m *MockOwnership) ListBitmarksFor(arg0 *account.Account, arg1 uint64, arg2 int) ([]ownership.Record, error) { 46 | m.ctrl.T.Helper() 47 | ret := m.ctrl.Call(m, "ListBitmarksFor", arg0, arg1, arg2) 48 | ret0, _ := ret[0].([]ownership.Record) 49 | ret1, _ := ret[1].(error) 50 | return ret0, ret1 51 | } 52 | 53 | // ListBitmarksFor indicates an expected call of ListBitmarksFor 54 | func (mr *MockOwnershipMockRecorder) ListBitmarksFor(arg0, arg1, arg2 interface{}) *gomock.Call { 55 | mr.mock.ctrl.T.Helper() 56 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBitmarksFor", reflect.TypeOf((*MockOwnership)(nil).ListBitmarksFor), arg0, arg1, arg2) 57 | } 58 | -------------------------------------------------------------------------------- /rpc/ratelimit/limit.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package ratelimit 7 | 8 | import ( 9 | "time" 10 | 11 | "golang.org/x/time/rate" 12 | 13 | "github.com/bitmark-inc/bitmarkd/fault" 14 | ) 15 | 16 | // limiting for a single request 17 | func Limit(limiter *rate.Limiter) error { 18 | r := limiter.Reserve() 19 | if !r.OK() { 20 | return fault.RateLimiting 21 | } 22 | time.Sleep(r.Delay()) 23 | return nil 24 | } 25 | 26 | // limiting for a multiple request 27 | func LimitN(limiter *rate.Limiter, count int, maximumCount int) error { 28 | // invalid count gets limited as a single request 29 | if count <= 0 || count > maximumCount { 30 | 31 | r := limiter.Reserve() 32 | if !r.OK() { 33 | return fault.RateLimiting 34 | } 35 | time.Sleep(r.Delay()) 36 | 37 | return fault.InvalidCount 38 | } 39 | 40 | r := limiter.ReserveN(time.Now(), count) 41 | if !r.OK() { 42 | return fault.RateLimiting 43 | } 44 | time.Sleep(r.Delay()) 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /rpc/ratelimit/limit_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package ratelimit_test 7 | -------------------------------------------------------------------------------- /rpc/transaction/transaction.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package transaction 7 | 8 | import ( 9 | "time" 10 | 11 | "github.com/bitmark-inc/bitmarkd/fault" 12 | "github.com/bitmark-inc/bitmarkd/merkle" 13 | "github.com/bitmark-inc/bitmarkd/reservoir" 14 | "github.com/bitmark-inc/bitmarkd/rpc/ratelimit" 15 | "github.com/bitmark-inc/logger" 16 | "golang.org/x/time/rate" 17 | ) 18 | 19 | const ( 20 | rateLimitTransaction = 200 21 | rateBurstTransaction = 100 22 | ) 23 | 24 | // Transaction - an RPC entry for transaction related functions 25 | type Transaction struct { 26 | Log *logger.L 27 | Limiter *rate.Limiter 28 | Start time.Time 29 | Rsvr reservoir.Reservoir 30 | ReadOnly bool 31 | } 32 | 33 | // Arguments - arguments for status RPC request 34 | type Arguments struct { 35 | TxId merkle.Digest `json:"txId"` 36 | } 37 | 38 | // StatusReply - results from status RPC 39 | type StatusReply struct { 40 | Status string `json:"status"` 41 | } 42 | 43 | func New(log *logger.L, 44 | start time.Time, 45 | rsvr reservoir.Reservoir, 46 | readOnly bool, 47 | ) *Transaction { 48 | return &Transaction{ 49 | Log: log, 50 | Limiter: rate.NewLimiter(rateLimitTransaction, rateBurstTransaction), 51 | Start: start, 52 | Rsvr: rsvr, 53 | ReadOnly: readOnly, 54 | } 55 | } 56 | 57 | // Status - query transaction status 58 | func (t *Transaction) Status(arguments *Arguments, reply *StatusReply) error { 59 | if err := ratelimit.Limit(t.Limiter); err != nil { 60 | return err 61 | } 62 | 63 | if t.Rsvr == nil { 64 | return fault.MissingReservoir 65 | } 66 | 67 | reply.Status = t.Rsvr.TransactionStatus(arguments.TxId).String() 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /rpc/transaction/transaction_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package transaction_test 7 | 8 | import ( 9 | "testing" 10 | "time" 11 | 12 | "github.com/golang/mock/gomock" 13 | "github.com/stretchr/testify/assert" 14 | 15 | "github.com/bitmark-inc/bitmarkd/fault" 16 | "github.com/bitmark-inc/bitmarkd/merkle" 17 | "github.com/bitmark-inc/bitmarkd/reservoir" 18 | "github.com/bitmark-inc/bitmarkd/rpc/fixtures" 19 | "github.com/bitmark-inc/bitmarkd/rpc/mocks" 20 | "github.com/bitmark-inc/bitmarkd/rpc/transaction" 21 | "github.com/bitmark-inc/logger" 22 | ) 23 | 24 | func TestTransactionStatus(t *testing.T) { 25 | fixtures.SetupTestLogger() 26 | defer fixtures.TeardownTestLogger() 27 | 28 | ctl := gomock.NewController(t) 29 | defer ctl.Finish() 30 | 31 | r := mocks.NewMockReservoir(ctl) 32 | 33 | now := time.Now() 34 | 35 | tr := transaction.New(logger.New(fixtures.LogCategory), now, r) 36 | 37 | arg := transaction.Arguments{TxId: merkle.Digest{1, 2, 3, 4}} 38 | 39 | r.EXPECT().TransactionStatus(arg.TxId).Return(reservoir.StateConfirmed).Times(1) 40 | 41 | var reply transaction.StatusReply 42 | err := tr.Status(&arg, &reply) 43 | assert.Nil(t, err, "wrong Status") 44 | assert.Equal(t, reservoir.StateConfirmed.String(), reply.Status, "") 45 | } 46 | 47 | func TestTransactionStatusWhenReservoirEmpty(t *testing.T) { 48 | fixtures.SetupTestLogger() 49 | defer fixtures.TeardownTestLogger() 50 | 51 | ctl := gomock.NewController(t) 52 | defer ctl.Finish() 53 | 54 | now := time.Now() 55 | 56 | tr := transaction.New(logger.New(fixtures.LogCategory), now, nil) 57 | 58 | arg := transaction.Arguments{TxId: merkle.Digest{1, 2, 3, 4}} 59 | 60 | var reply transaction.StatusReply 61 | err := tr.Status(&arg, &reply) 62 | assert.NotNil(t, err, "wrong Status") 63 | assert.Equal(t, fault.MissingReservoir, err, "wrong error message") 64 | } 65 | -------------------------------------------------------------------------------- /scripts/add-license: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ensure all go files have a license header 3 | 4 | year=$(date '+%Y') 5 | license_regex='SPDX-License-Identifier:' 6 | 7 | find . -type f -name '*.go' -print | ( 8 | while read filename 9 | do 10 | egrep -q -m 1 "${license_regex}" "${filename}" 11 | rc_license="${?}" 12 | 13 | egrep -q -m 1 'Copyright[[:space:]][(]c[)].*Bitmark[[:space:]]Inc[.]' "${filename}" 14 | rc_copyright="${?}" 15 | 16 | ok='' 17 | [ "${rc_license}" -ne 0 ] && ok='!L' 18 | [ "${rc_copyright}" -ne 0 ] && ok="${ok}"'!C' 19 | [ -z "${ok}" ] && ok=OK 20 | 21 | printf 'file: %-4s %s\n' "${ok}" "${filename}" 22 | [ X"${ok}" = X"OK" ] && continue 23 | 24 | backup="${filename}.bk" 25 | rm -f "${backup}" 26 | mv "${filename}" "${backup}" 27 | 28 | if [ "${rc_license}" -ne 0 ] || [ "${rc_copyright}" -ne 0 ] 29 | then 30 | printf '// SPDX-License-Identifier: ISC\n' >> "${filename}" 31 | fi 32 | 33 | if [ "${rc_copyright}" -ne 0 ] 34 | then 35 | printf '// Copyright (c) 2014-%d Bitmark Inc.\n' "${year}" >> "${filename}" 36 | printf '// Use of this source code is governed by an ISC\n' >> "${filename}" 37 | printf '// license that can be found in the LICENSE file.\n' >> "${filename}" 38 | printf '\n' >> "${filename}" 39 | fi 40 | 41 | egrep -v "${license_regex}" "${backup}" >> "${filename}" 42 | 43 | done 44 | ) 45 | -------------------------------------------------------------------------------- /scripts/list-dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # track currently active module dependencies 3 | 4 | ERROR() 5 | { 6 | echo error: $* 7 | exit 1 8 | } 9 | 10 | [ -d "${GOPATH}" ]|| ERROR "missing directory: ${GOPATH}" 11 | 12 | os=$(uname -s | tr 'A-Z' 'a-z') 13 | machine=$(uname -m | tr 'A-Z' 'a-z') 14 | account=$(basename "$(dirname "${PWD}")") 15 | application=$(basename "${PWD}") 16 | 17 | pkg="${GOPATH}/pkg/${os}_${machine}/github.com/${account}/${application}" 18 | [ -d "${pkg}" ] || error "missing directory: ${pkg}" 19 | 20 | list=$(ls -1 "${pkg}" | grep '\.a$' | sed 's/\.a$//') 21 | 22 | list="${list} command/bitmarkd" 23 | 24 | for d in ${list} 25 | do 26 | [ X"${d}" != X"${d#-}" ] && continue 27 | printf '===> %s\n' "${d}" 28 | go list -f '{{join .Deps "\n "}}' ${d}/*.go | sort -u | grep 'github' 29 | echo 30 | done 31 | 32 | echo 'No library for:' 33 | for d in * 34 | do 35 | [ -d "${d}" ] || continue 36 | [ -f "${pkg}/${d}.a" ] && continue 37 | printf ' %s\n' "${d}" 38 | done 39 | -------------------------------------------------------------------------------- /scripts/list-rpcs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # scan go files in rpc/ and print Class.Method for all client APIs 3 | 4 | awk ' 5 | /^func[[:space:]][(][[:alpha:]]+.*[[:space:]]error[[:space:]]/ { 6 | split($4, fn, "[(]") # expect: Method(arguments 7 | split($3, type, "[*)]") # expect: *TYPE) 8 | if (3 == length(type) && 2 == length(fn)) { 9 | if ("InternalConnection" != type[2]) { 10 | print type[2] "." fn[1] 11 | } 12 | } 13 | } 14 | 15 | /^func[[:space:]][(][[:alpha:]]+[[:space:]]+[*]httpHandler/ { 16 | split($4, fn, "[(]") # expect: Method(arguments 17 | split($3, type, "[*)]") # expect: *TYPE) 18 | if (3 == length(type) && 2 == length(fn)) { 19 | print "https://.../" fn[1] 20 | } 21 | } 22 | 23 | 24 | ' rpc/*/*.go | sort 25 | -------------------------------------------------------------------------------- /scripts/need-fixes: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # print files needing fixes 3 | 4 | for d in * 5 | do 6 | [ ! -d "${d}" ] && continue 7 | [ X"${d}" = X"OLD" ] && continue 8 | 9 | flag=no 10 | grep -rc '[*] FIX THIS:' "${d}" | grep -v ':0$' | sed 's/:\([0-9]*\)$/ \1/' | \ 11 | while read file count junk 12 | do 13 | if [ X"${flag}" = X"no" ] 14 | then 15 | flag=yes 16 | printf '%s\n' "${d}" 17 | fi 18 | printf ' %s (%d)\n' "${file#${d}/}" "${count}" 19 | done 20 | done 21 | -------------------------------------------------------------------------------- /scripts/setup-hooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ERROR_CODE=1 4 | SUCCESS_CODE=0 5 | 6 | current_path=$(pwd) 7 | 8 | # check if this script runs at bitmarkd root directory 9 | if [[ ! "$current_path" == *bitmarkd ]]; then 10 | printf "\nCurrent directory ${current_path}, please run script at bitmarkd root directory.\n" 11 | exit $ERROR_CODE 12 | fi 13 | 14 | git_dir="${current_path}/.git" 15 | hook_dir="${git_dir}/hooks" 16 | 17 | # backup git hooks directory 18 | if [ -d $hook_dir ] && [ ! -L $hook_dir ]; then 19 | timestamp=$(date +%s) 20 | backup_dir="hooks-backup-${timestamp}" 21 | printf "backup existing hooks directory into ${backup_dir}..." 22 | mv $hook_dir "${git_dir}/${backup_dir}" 23 | fi 24 | 25 | # do nothing if already linked 26 | if [ -d $hook_dir ] && [ -L $hook_dir ]; then 27 | printf "${hook_dir} already exist, exit..." 28 | exit $SUCCESS_CODE 29 | fi 30 | 31 | # link hook directory 32 | if [ -d "${current_path}/hooks" ]; then 33 | printf '\nLink hook directory...\n' 34 | cd $git_dir 35 | ln -s ../hooks 36 | cd $current_path 37 | else 38 | printf "\nError: hooks directory not exist, abort...\n" 39 | exit $ERROR_CODE 40 | fi 41 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=bitmark:bitmarkd 2 | sonar.projectName=Bitmarkd 3 | sonar.projectVersion=1.0 4 | sonar.sources=. 5 | sonar.sourceEncoding=UTF-8 6 | -------------------------------------------------------------------------------- /storage/cache.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package storage 7 | 8 | import ( 9 | "time" 10 | 11 | cache "github.com/patrickmn/go-cache" 12 | ) 13 | 14 | type Cache interface { 15 | Get(string) ([]byte, bool) 16 | Set(int, string, []byte) 17 | Clear() 18 | } 19 | 20 | const ( 21 | dbPut = iota 22 | dbDelete 23 | ) 24 | 25 | const ( 26 | defaultTimeout = 1 * time.Minute 27 | defaultExpiration = 2 * time.Minute 28 | ) 29 | 30 | type dbCache struct { 31 | cache *cache.Cache 32 | } 33 | 34 | type cacheData struct { 35 | op int 36 | value []byte 37 | } 38 | 39 | func newCache() Cache { 40 | return &dbCache{ 41 | cache: cache.New(defaultTimeout, defaultExpiration), 42 | } 43 | } 44 | 45 | func (c *dbCache) Get(key string) ([]byte, bool) { 46 | obj, found := c.cache.Get(key) 47 | if !found { 48 | return []byte{}, found 49 | } 50 | 51 | data := obj.(cacheData) 52 | // if key is deleted, then cache should return not found 53 | if dbDelete == data.op { 54 | return []byte{}, false 55 | } 56 | 57 | return data.value, found 58 | } 59 | 60 | func (c *dbCache) Set(op int, key string, value []byte) { 61 | cached := cacheData{ 62 | op: op, 63 | value: value, 64 | } 65 | c.cache.Set(key, cached, defaultExpiration) 66 | } 67 | 68 | func (c *dbCache) Clear() { 69 | c.cache.Flush() 70 | } 71 | -------------------------------------------------------------------------------- /storage/cache_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package storage 7 | 8 | import ( 9 | "testing" 10 | ) 11 | 12 | func setupTestCache() Cache { 13 | return newCache() 14 | } 15 | 16 | func isSameByteSlice(a []byte, b []byte) bool { 17 | if len(a) != len(b) { 18 | return false 19 | } 20 | 21 | for i, v := range a { 22 | if v != b[i] { 23 | return false 24 | } 25 | } 26 | 27 | return true 28 | } 29 | 30 | func TestWriteThenRead(t *testing.T) { 31 | cache := setupTestCache() 32 | 33 | key := "test" 34 | expected := []byte{'a', 'b', 'c', 'd'} 35 | 36 | actual, found := cache.Get(key) 37 | 38 | if found { 39 | t.Errorf("error key %s already exist value %v\n", key, actual) 40 | } 41 | 42 | cache.Set(dbPut, key, expected) 43 | actual, found = cache.Get(key) 44 | 45 | if !found || !isSameByteSlice(actual, expected) { 46 | t.Errorf("error set key %s, expect %v but get %v\n", key, expected, actual) 47 | } 48 | } 49 | 50 | func TestClear(t *testing.T) { 51 | cache := setupTestCache() 52 | 53 | key := "test" 54 | data := []byte{'a', 'b', 'c', 'd'} 55 | 56 | cache.Set(dbPut, key, data) 57 | cache.Clear() 58 | 59 | _, found := cache.Get(key) 60 | if found { 61 | t.Errorf("error Clear not working, expect cache is empty but not") 62 | } 63 | } 64 | 65 | func TestReadDeleteOperation(t *testing.T) { 66 | cache := setupTestCache() 67 | 68 | key := "test" 69 | data := []byte{'a', 'b', 'c', 'd'} 70 | 71 | cache.Set(dbDelete, key, data) 72 | 73 | _, found := cache.Get(key) 74 | if found { 75 | t.Errorf("delete operation should get nothing") 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /testing/create-node-users.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # this sets a default easy to guess password 3 | 4 | 5 | ERROR() { 6 | printf 'error: ' 7 | # shellcheck disable=SC2059 8 | printf -- "$@" 9 | printf '\n' 10 | exit 1 11 | } 12 | 13 | 14 | # main program 15 | 16 | first_node=1 17 | last_node=12 18 | 19 | password=1234567890 20 | [ -n "${1}" ] && password="${1}" 21 | 22 | xdg_home="${XDG_CONFIG_HOME}" 23 | [ -z "${xdg_home}" ] && xdg_home="${HOME}/.config" 24 | [ -d "${xdg_home}" ] || ERROR 'missing directory: "%s" please create first' "${xdg_home}" 25 | 26 | # create first and second users 27 | bitmark-cli --network=local --identity=first --password="${password}" setup --connect=127.0.0.1:22130 --description='first user' --new 28 | bitmark-cli --network=local --identity=second --password="${password}" add --description='second user' --new 29 | 30 | # create users for all bitmarkds 31 | for i in $(seq "${first_node}" "${last_node}") 32 | do 33 | id="node-${i}" 34 | seed="${xdg_home}/bitmarkd${i}/proof.test" 35 | [ -f "${seed}" ] || ERROR 'missing file: %s' "${seed}" 36 | bitmark-cli --network=local --identity="${id}" --password="${password}" add --description="node ${i}" --seed="$(cat "${seed}")" 37 | done 38 | -------------------------------------------------------------------------------- /testing/genbtcltc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ensure both local chains get a new block 3 | 4 | n=1 5 | [ -n "${1}" ] && n="${1}" 6 | 7 | #run-bitcoin generate "${n}" 8 | #run-litecoin generate "${n}" 9 | 10 | btc_address="$(run-bitcoin getnewaddress)" 11 | ltc_address="$(run-litecoin getnewaddress)" 12 | 13 | run-bitcoin generatetoaddress "${n}" "${btc_address}" 14 | run-litecoin generatetoaddress "${n}" "${ltc_address}" 15 | -------------------------------------------------------------------------------- /testing/samples/bitcoin.conf: -------------------------------------------------------------------------------- 1 | # bitcoin.conf 2 | 3 | regtest = 1 4 | dnsseed = 0 5 | gen = 0 6 | 7 | reindex = 1 8 | txindex = 1 9 | 10 | upnp = 0 11 | alertnotify = echo %s | mail -s "Bitcoin Alert (local testing)" root@localhost 12 | 13 | # default is bitcoind.pid - but be explicit since litecoin uses the same default 14 | pid = bitcoind.pid 15 | 16 | [regtest] 17 | 18 | # peer port 19 | port = 18444 20 | bind = 127.0.0.1 21 | bind = [::1] 22 | 23 | discover = 0 24 | listenonion = 0 25 | 26 | # peer connections 27 | #connect = 127.1.2.3:18002 28 | 29 | # always run a server 30 | server = 1 31 | listen = 1 32 | rest = 1 33 | 34 | # logging 35 | #debug = alert 36 | 37 | # ZMQ publishing 38 | zmqpubhashblock = tcp://127.0.0.1:18449 39 | zmqpubhashblock = tcp://[::1]:18449 40 | zmqpubhashtx = tcp://127.0.0.1:18449 41 | zmqpubhashtx = tcp://[::1]:18449 42 | #zmqpubrawblock = tcp://127.0.0.1:18449 43 | #zmqpubrawtx = tcp://127.0.0.1:18449 44 | 45 | 46 | # RPC server port 47 | rpcport = 18443 48 | rpcbind = 127.0.0.1 49 | rpcbind = [::1] 50 | 51 | # RPC configuration 52 | rpcthreads = 20 53 | #rpcssl = 1 54 | rpcallowip = 127.0.0.1 55 | rpcallowip = [::1] 56 | 57 | rpcauth = asgymsscumjvwluanhpmzhhc:1357811ab35f8be1e1f97a846f12f$bef3bff921680f79877ebe61dcd2d6f43c271b33ba7682b82c6ac8a4978642ac 58 | ## username: "asgymsscumjvwluanhpmzhhc" 59 | ## password: "cuh-OAHtwo6-4ZsXvm8syxthCmV8oyHY07T1oHm18-c=" 60 | -------------------------------------------------------------------------------- /testing/samples/litecoin.conf: -------------------------------------------------------------------------------- 1 | # litecoin.conf 2 | 3 | regtest = 1 4 | dnsseed = 0 5 | gen = 0 6 | 7 | reindex = 1 8 | txindex = 1 9 | 10 | upnp = 0 11 | alertnotify = echo %s | mail -s "Litecoin Alert (local testing)" root@localhost 12 | 13 | # default is bitcoind.pid - change to avoid confusion 14 | pid = litecoind.pid 15 | 16 | [regtest] 17 | 18 | # peer port 19 | port = 19444 20 | bind = 127.0.0.1 21 | bind = [::1] 22 | 23 | discover = 0 24 | listenonion = 0 25 | 26 | # peer connections 27 | #connect = 127.1.2.3:19002 28 | 29 | # always run a server 30 | server = 1 31 | listen = 1 32 | rest = 1 33 | 34 | # logging 35 | #debug = alert 36 | 37 | # ZMQ publishing 38 | zmqpubhashblock = tcp://127.0.0.1:19449 39 | zmqpubhashblock = tcp://[::1]:19449 40 | zmqpubhashtx = tcp://127.0.0.1:19449 41 | zmqpubhashtx = tcp://[::1]:19449 42 | #zmqpubrawblock = tcp://127.0.0.1:19449 43 | #zmqpubrawtx = tcp://127.0.0.1:19449 44 | 45 | 46 | # RPC server port 47 | rpcport = 19443 48 | rpcbind = 127.0.0.1 49 | rpcbind = [::1] 50 | 51 | # RPC configuration 52 | rpcthreads = 20 53 | #rpcssl = 1 54 | rpcallowip = 127.0.0.1 55 | rpcallowip = [::1] 56 | 57 | rpcauth = xehjpioqyawynunxknoawpun:be2329ad47d61b5d8295276328716cca$f3a6fa3137e26907ed5be3a21fe0de07714b0874d1bb578639489bdbbb5d8373 58 | ## username: "xehjpioqyawynunxknoawpun" 59 | ## password: "OGjFWI5zkuVTQ4fdiCfbPvRO8hJN2gV_qv0syEDr-6g=" 60 | -------------------------------------------------------------------------------- /transactionrecord/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package transactionrecord - the structure of the transaction records 7 | // 8 | // includes functions to pack/unpack []byte form 9 | package transactionrecord 10 | -------------------------------------------------------------------------------- /util/base58.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2013-2014 Conformal Systems LLC. 3 | // Copyright (c) 2014-2020 Bitmark Inc. 4 | // Use of this source code is governed by an ISC 5 | // license that can be found in the LICENSE file. 6 | 7 | package util 8 | 9 | import ( 10 | "math/big" 11 | "strings" 12 | ) 13 | 14 | // alphabet is the modified base58 alphabet used by Bitcoin. 15 | const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 16 | 17 | var bigRadix = big.NewInt(58) 18 | var bigZero = big.NewInt(0) 19 | 20 | // FromBase58 decodes a modified base58 string to a byte slice. 21 | func FromBase58(b string) []byte { 22 | answer := big.NewInt(0) 23 | j := big.NewInt(1) 24 | 25 | for i := len(b) - 1; i >= 0; i-- { 26 | tmp := strings.IndexAny(alphabet, string(b[i])) 27 | if tmp == -1 { 28 | return []byte("") 29 | } 30 | idx := big.NewInt(int64(tmp)) 31 | tmp1 := big.NewInt(0) 32 | tmp1.Mul(j, idx) 33 | 34 | answer.Add(answer, tmp1) 35 | j.Mul(j, bigRadix) 36 | } 37 | 38 | tmpval := answer.Bytes() 39 | 40 | var numZeros int 41 | loop: 42 | for numZeros = 0; numZeros < len(b); numZeros++ { 43 | if b[numZeros] != alphabet[0] { 44 | break loop 45 | } 46 | } 47 | flen := numZeros + len(tmpval) 48 | val := make([]byte, flen) 49 | copy(val[numZeros:], tmpval) 50 | 51 | return val 52 | } 53 | 54 | // ToBase58 encodes a byte slice to a modified base58 string. 55 | func ToBase58(b []byte) string { 56 | x := new(big.Int) 57 | x.SetBytes(b) 58 | 59 | answer := make([]byte, 0, len(b)*136/100) 60 | for x.Cmp(bigZero) > 0 { 61 | mod := new(big.Int) 62 | x.DivMod(x, bigRadix, mod) 63 | answer = append(answer, alphabet[mod.Int64()]) 64 | } 65 | 66 | // leading zero bytes 67 | loop: 68 | for _, i := range b { 69 | if i != 0 { 70 | break loop 71 | } 72 | answer = append(answer, alphabet[0]) 73 | } 74 | 75 | // reverse 76 | alen := len(answer) 77 | for i := 0; i < alen/2; i++ { 78 | answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i] 79 | } 80 | 81 | return string(answer) 82 | } 83 | -------------------------------------------------------------------------------- /util/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package util - miscellaneous small routines 7 | package util 8 | -------------------------------------------------------------------------------- /util/fetcher.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package util 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "io/ioutil" 12 | "net/http" 13 | ) 14 | 15 | // FetchJSON - fetch a JSON response from an HTTP request and decode 16 | // it 17 | func FetchJSON(client *http.Client, url string, reply interface{}) error { 18 | request, err := http.NewRequest("GET", url, http.NoBody) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | response, err := client.Do(request) 24 | if err != nil { 25 | return err 26 | } 27 | defer response.Body.Close() 28 | body, err := ioutil.ReadAll(response.Body) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | if http.StatusOK != response.StatusCode { 34 | return fmt.Errorf("status: %d %q on: %q", response.StatusCode, response.Status, url) 35 | } 36 | return json.Unmarshal(body, &reply) 37 | } 38 | -------------------------------------------------------------------------------- /util/formatbytes.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package util 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | ) 12 | 13 | // FormatBytes - for dumping the expected hex used by some test 14 | // routines 15 | func FormatBytes(name string, data []byte) string { 16 | a := strings.Split(fmt.Sprintf("% #x", data), " ") 17 | s := name + " := []byte{" 18 | n := 8 19 | for i := 0; i < len(a); i += 1 { 20 | n += 1 21 | if n >= 8 { 22 | s += "\n\t" 23 | n = 0 24 | } 25 | s += a[i] + ", " 26 | } 27 | return s + "\n}" 28 | } 29 | -------------------------------------------------------------------------------- /util/paths.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package util 7 | 8 | import ( 9 | "os" 10 | "path/filepath" 11 | ) 12 | 13 | // EnsureAbsolute - ensure the path is absolute 14 | // if not, prepend the directory to make absolute path 15 | func EnsureAbsolute(directory string, filePath string) string { 16 | if !filepath.IsAbs(filePath) { 17 | filePath = filepath.Join(directory, filePath) 18 | } 19 | return filepath.Clean(filePath) 20 | } 21 | 22 | // EnsureFileExists - check if file exists 23 | func EnsureFileExists(name string) bool { 24 | _, err := os.Stat(name) 25 | return err == nil 26 | } 27 | -------------------------------------------------------------------------------- /zmqutil/authentication.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package zmqutil 7 | 8 | import ( 9 | "sync" 10 | 11 | zmq "github.com/pebbe/zmq4" 12 | ) 13 | 14 | // to ensure only one auth start 15 | var oneTimeAuthStart sync.Once 16 | 17 | // StartAuthentication - initialise the ZMQ security subsystem 18 | func StartAuthentication() error { 19 | 20 | err := error(nil) 21 | oneTimeAuthStart.Do(func() { 22 | 23 | // initialise encryption 24 | zmq.AuthSetVerbose(false) 25 | //zmq.AuthSetVerbose(true) 26 | err = zmq.AuthStart() 27 | }) 28 | 29 | return err 30 | } 31 | -------------------------------------------------------------------------------- /zmqutil/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package zmqutil - various comm ZMq routines shared be all commands 7 | package zmqutil 8 | -------------------------------------------------------------------------------- /zmqutil/monitor.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package zmqutil 7 | 8 | import ( 9 | zmq "github.com/pebbe/zmq4" 10 | ) 11 | 12 | // NewMonitor - return a socket connection to the monitoring channel of another socket 13 | // for connection state signalling 14 | // a unique inproc://name must be provided for each use 15 | func NewMonitor(socket *zmq.Socket, connection string, event zmq.Event) (*zmq.Socket, error) { 16 | 17 | err := socket.Monitor(connection, event) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | mon, err := zmq.NewSocket(zmq.PAIR) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | err = mon.Connect(connection) 28 | if err != nil { 29 | mon.Close() 30 | return nil, err 31 | } 32 | 33 | return mon, nil 34 | } 35 | -------------------------------------------------------------------------------- /zmqutil/zmqutil_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | // Copyright (c) 2014-2020 Bitmark Inc. 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package zmqutil 7 | --------------------------------------------------------------------------------