Code Monkey home page Code Monkey logo

lbcd's Introduction

lbcd

Build Status Coverage Status ISC License

lbcd is a full node implementation of LBRY's blockchain written in Go (golang).

Software stack developed by LBRY teams has been all migrated to lbcd.

We're working with exchanges and pool oerators to migrate from lbrycrd to lbcd.

If you're integrating with lbcd+lbcwallet, please check the Wiki for current supported RPCs.

Note: lbcd does NOT include wallet functionality. That functionality is provided by the lbcwallet and the LBRY SDK.

Requirements

All common operating systems are supported. lbcd requires at least 8GB of RAM and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time. Using a fast NVMe disk is recommended.

Installation

Acquire binary files from releases

For compilation, Go 1.19 or newer is required. Install Go according to its installation instructions.

# lbcd (full node)
$ go install github.com/lbryio/lbcd@latest

# lbcctl (rpc client utility)
$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest

Usage

Default application folder ${LBCDDIR}:

  • Linux: ~/.lbcd/
  • MacOS: /Users/<username>/Library/Application Support/Lbcd/

Start the lbcd

./lbcd

lbcd loads config file at "${LBCDDIR}/lbcd.conf".

If no config is found, it creates a default one, which includes all available options with default settings except randomly generated RPC credentials (see below).

RPC server

RPC credentials (rpcuser and rpcpass) is required to enable RPC server. It can be specify in the "${LBCDDIR}/lbcd.conf", using command line options:

./lbcd --rpcuser=rpcuser --rpcpass=rpcpass

2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on 0.0.0.0:9245
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on [::]:9245

Working with TLS (Default)

By default, lbcd runs RPC server with TLS enabled, and generates the rpc.cert and rpc.key under ${LBCDDIR}, if not exist already.

To interact with the RPC server, a client has to either specify the rpc.cert, or disable the certification verification for TLS.

Interact with lbcd RPC using lbcctl

$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount

# or disable the certificate verification
$ ./lbcctl --skipverify getblockcount

1200062

Interact with lbcd RPC using curl

$ curl --user rpcuser:rpcpass \
        --cacert "${LBCDDIR}/rpc.cert" \
        --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
        -H 'content-type: text/plain;' \
        https://127.0.0.1:9245/

# or disable the certificate verification
$ curl --user rpcuser:rpcpass \
        --insecure \
        --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
        -H 'content-type: text/plain;' \
        https://127.0.0.1:9245/
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}

Working without TLS

TLS can be disabled using the --notls option:

$ ./lbcd --notls
$ ./lbcctl --notls getblockcount

1200062
$ curl --user rpcuser:rpcpass \
        --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
        -H 'content-type: text/plain;' \
        http://127.0.0.1:9245/
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}

Using Snapshots (optional)

Snapshots are created bi-weekly to help new users catch up current block height.

The snapshots are archived and compressed in zstd format for it's compression ratio and speed.

Download the snapshot, and uncompress it:

time curl -O https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst
zstd -d --stdout lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | tar xf - -C "${LBCDDIR}"

If preferred, a user can download and uncompress the snapshot on the fly: By the time the download is finished, the snapshots should be almost uncompressed already.

mkdir -p "${LBCDDIR}"

time curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | zstd -d --stdout | tar xf - -C "${LBCDDIR}"

#  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
#                                 Dload  Upload   Total   Spent    Left  Speed
# 100 64.9G  100 64.9G    0     0  37.0M      0  0:29:49  0:29:49 --:--:-- 33.0M
#
# real    29m49.962s
# user    6m53.710s
# sys     8m56.545s

Working with RPCs

Using lbcctl -l to list available RPCs:

$ lbcctl -l

Chain Server Commands:
addnode "addr" "add|remove|onetry"
createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)
debuglevel "levelspec"
decoderawtransaction "hextx"
decodescript "hexscript"
deriveaddresses "descriptor" ({"value":value})
fundrawtransaction "hextx" {"changeaddress":changeaddress,"changeposition":changeposition,"changetype":changetype,"includewatching":includewatching,"lockunspents":lockunspents,"feerate":feerate,"subtractfeefromoutputs":[subtractfeefromoutput,...],"replaceable":replaceable,"conftarget":conftarget,"estimatemode":estimatemode} (iswitness)
generate numblocks

[skipped]

Wallet Server Commands (--wallet):
addmultisigaddress nrequired ["key",...] ("account")
addwitnessaddress "address"
backupwallet "destination"
createmultisig nrequired ["key",...]
createnewaccount "account"
createwallet "walletname" (disableprivatekeys=false blank=false passphrase="" avoidreuse=false)
dumpprivkey "address"
dumpwallet "filename"
encryptwallet "passphrase"
estimatefee numblocks
estimatepriority numblocks
estimatesmartfee conftarget (estimatemode="CONSERVATIVE")
getaccount "address"
getaccountaddress "account"
getaddressesbyaccount "account"

[skipped]

Using lbcctl help rpcname to show the RPC spec:

$ lbcctl help getblock

getblock "hash" (verbosity=1)

Returns information about a block given its hash.

Arguments:
1. hash      (string, required)             The hash of the block
2. verbosity (numeric, optional, default=1) Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2)

Result (verbosity=0):
"value" (string) Hex-encoded bytes of the serialized block

Result (verbosity=1):
{
 "getblockverboseresultbase": { (object)
  "hash": "value",              (string)          The hash of the block (same as provided)
  "confirmations": n,           (numeric)         The number of confirmations
  "strippedsize": n,            (numeric)         The size of the block without witness data
  "size": n,                    (numeric)         The size of the block
  "weight": n,                  (numeric)         The weight of the block
  "height": n,                  (numeric)         The height of the block in the block chain
  "version": n,                 (numeric)         The block version
  "versionHex": "value",        (string)          The block version in hexadecimal
  "merkleroot": "value",        (string)          Root hash of the merkle tree
  "time": n,                    (numeric)         The block time in seconds since 1 Jan 1970 GMT
  "mediantime": n,              (numeric)         The median block time in seconds since 1 Jan 1970 GMT
  "nonce": n,                   (numeric)         The block nonce
  "bits": "value",              (string)          The bits which represent the block difficulty
  "difficulty": n.nnn,          (numeric)         The proof-of-work difficulty as a multiple of the minimum difficulty
  "chainwork": "value",         (string)          Expected number of hashes required to produce the chain up to this block (in hex)
  "previousblockhash": "value", (string)          The hash of the previous block
  "nextblockhash": "value",     (string)          The hash of the next block (only if there is one)
  "nameclaimroot": "value",     (string)          Root hash of the claim trie
  "nTx": n,                     (numeric)         The number of transactions (aka, count of TX)
 },
 "tx": ["value",...],           (array of string) The transaction hashes (only when verbosity=1)
}

lbcd & lbcwallet

Wallet related functianlities and RPCs are provided by a separate programe - lbcwallet.

Once setup, lbcwallet can serve wallet related RPCs as well as proxy lbcd RPCs to an assocated lbcd now. It's sufficient for user to connect just the lbcwallet instead of both.

sequenceDiagram
    actor C as lbcctl
    participant W as lbcwallet (port: 9244)
    participant D as lbcd (port: 9245)

    rect rgb(200,200,200)
    Note over C,D: lbcctl getblockcount
    C ->>+ D: getblockcount
    D -->>- C: response
    end

    rect rgb(200,200,200)
    Note over C,W: lbcctl --wallet balance
    C ->>+ W: getbalance
    W -->>- C: response
    end

    rect rgb(200,200,200)
    Note over C,D: lbcctl --wallet getblockcount (lbcd RPC service proxied by lbcwallet)
    C ->>+ W: getblockcount
    W ->>+ D: getblockcount
    D -->>- W: response
    W -->>- C: response
    end
Loading

While lbcd can run standalone as a full node, lbcwallet requires an associated lbcd instance for scanning and sync'ing block data.

sequenceDiagram
    participant W as lbcwallet (RPC port: 9244)
    participant D as lbcd (RPC port: 9245, P2P port: 9246)
    participant D2 as other lbcd node(s) (P2P port: 9246)

    rect rgb(200,200,200)
    Note over W,D: Asynchronous websocket notifications
    W ->> D: subscribe to notifications
    D -->> W: notification
    D -->> W: notification
    end

    rect rgb(200,200,200)
    Note over W,D: lbcd RPCs
    W ->>+ D: getblockheader
    D ->>- W: response
    end

    rect rgb(200,200,200)
    Note over D,D2: P2P messages over port 9246
    D -->> D2: P2P message
    D2 -->> D: P2P message
    end

Loading

Data integrity

lbcd is not immune to data loss. It expects a clean shutdown via SIGINT or SIGTERM. SIGKILL, immediate VM kills, and sudden power loss can cause data corruption, thus requiring chain resynchronization for recovery.

Security

We take security seriously. Please contact security regarding any security issues. Our PGP key is here if you need it.

We maintain a mailing list for notifications of upgrades, security issues, and soft/hard forks. To join, visit fork list

Contributing

Contributions to this project are welcome, encouraged, and compensated. The integrated github issue tracker is used for this project. All pull requests will be considered.

License

lbcd is licensed under the copyfree ISC License.

lbcd's People

Contributors

0xmichalis avatar aakselrod avatar brannonking avatar cfromknecht avatar dajohi avatar davecgh avatar dirbaio avatar drahn avatar federicobond avatar flammit avatar guggero avatar halseth avatar jakesylvestre avatar jcvernaleo avatar jimmysong avatar jongillham avatar jrick avatar lindlof avatar martelletto avatar moodyjon avatar onyb avatar owainga avatar rjected avatar roasbeef avatar roylee17 avatar stevenroose avatar tsenart avatar tuxcanfly avatar wallclockbuilder avatar wpaulino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lbcd's Issues

Display progress during RamTrie rebuilding at (re)startup

lbcd rebuilds RamTrie at the startup, and this can take few minutes to half hour depend on the machine.
During the this time, the only visual changes from the log is periodic resource consumption report:

2022-06-03 20:04:28.330 [INF] MAIN: RAM: using 1.9 GB with 27.1 available, DISK: using 19.1 GB with 281.9 available
2022-06-03 20:04:38.340 [INF] MAIN: RAM: using 2.1 GB with 26.9 available, DISK: using 19.3 GB with 281.7 available
...

It would be good to show the progress even an estimate one.

Align dust calculation to lbrycrd

Currently, some low-value transactions are being considered dust and rejected by lbcd while accepted by lbrycrd.

Things to check:

-[ ] minRelayFee on both clients are the same, and in terms of KBC/KB or absolute value?
-[ ] Does lbrycrd rn with accepting non-standard enabled?
-[ ] The logic of dust calculation.

lbcd rejects other lbcd peers's `getdata` network message.

This can be reproduced by having a lbcd connected to only another lbcd instance.

lbcd --datadir=~/tmp/lbcd-test/datadir --logdir=~/tmp/lbcd-test/logdir --nolisten --norpc --connect 127.0.0.1:9246

The catching up (sync from scratch) node soon lost the peer and stuck since we indicate it to connect only one lbcd node.

2022-05-12 09:17:29.334 [INF] MAIN: RPC service is disabled
2022-05-12 09:17:29.335 [INF] MAIN: Version 0.22.200-beta
...
2022-05-12 09:17:29.985 [INF] SYNC: New valid peer 127.0.0.1:9246 (outbound) (/btcwire:0.5.0/LBRY.GO:0.22.200/)
2022-05-12 09:17:29.985 [INF] SYNC: Syncing to block height 1158573 from peer 127.0.0.1:9246
2022-05-12 09:17:29.985 [INF] SYNC: Downloading headers for blocks 1 to 40000 from peer 127.0.0.1:9246
2022-05-12 09:17:30.087 [INF] SYNC: Verified downloaded block header against checkpoint at height 40000/hash 4c55584b068108b15c0066a010d11971aa92f46b0a73d479f1b7fa57df8b05f4
2022-05-12 09:17:30.087 [INF] SYNC: Received 40000 block headers: Fetching blocks
2022-05-12 09:17:40.087 [INF] SYNC: Processed 16254 blocks in the last 10s (64833 transactions, height 16254, 2016-07-22 14:47:41 -0700 PDT)
2022-05-12 09:17:49.913 [INF] LBRY: Invalid update operation: name or ID mismatch at 25468 for: cookie21, f854f24c664c81a012f3bc7eca6b693d211e6bfd
2022-05-12 09:17:49.920 [INF] LBRY: Invalid update operation: name or ID mismatch at 25477 for: cookie22, 396b783e61d0e6844d08089dc6f6775f693b20e6
2022-05-12 09:17:49.927 [INF] LBRY: Invalid update operation: name or ID mismatch at 25480 for: pug, a97a7fd002dcea85afab0a0211342c7eb8237c4b
2022-05-12 09:17:49.940 [INF] LBRY: Invalid update operation: name or ID mismatch at 25489 for: pug, f13758adbce6204aa4b941059f3ba85bc4820e4a
2022-05-12 09:17:50.090 [INF] SYNC: Processed 9364 blocks in the last 10s (114463 transactions, height 25618, 2016-08-09 00:40:16 -0700 PDT)
2022-05-12 09:18:00.090 [INF] SYNC: Processed 8156 blocks in the last 10s (113434 transactions, height 33774, 2016-08-24 03:41:00 -0700 PDT)
2022-05-12 09:18:07.737 [INF] CHAN: Verified checkpoint at height 40000/block 4c55584b068108b15c0066a010d11971aa92f46b0a73d479f1b7fa57df8b05f4
2022-05-12 09:18:07.739 [INF] SYNC: Downloading headers for blocks 40001 to 80000 from peer 127.0.0.1:9246
2022-05-12 09:18:07.843 [INF] SYNC: Verified downloaded block header against checkpoint at height 80000/hash 6e9facdfb87ba8394a46c61a7c093f7f00b1397a2dabc6a04f2911e0efdcf50a
2022-05-12 09:18:07.843 [INF] SYNC: Received 40000 block headers: Fetching blocks
2022-05-12 09:18:08.022 [INF] SYNC: Lost peer 127.0.0.1:9246 (outbound)
2022-05-12 09:18:08.026 [WRN] SYNC: No sync peer candidates available

The other lbcd instance complains and ban the catching up node.

2022-05-12 09:18:08.022 [WRN] PEER: Misbehaving peer 127.0.0.1:57637 (inbound): getdata -- ban score increased to 129
2022-05-12 09:18:08.022 [WRN] PEER: Misbehaving peer 127.0.0.1:57637 (inbound) -- banning and disconnecting
2022-05-12 09:18:08.022 [INF] SRVR: Banned peer 127.0.0.1 (inbound) for 24h0m0s
2022-05-12 09:18:08.022 [INF] SYNC: Lost peer 127.0.0.1:57637 (inbound)
2022-05-12 09:18:11.939 [INF] MAIN: RAM: using 5.7 GB with 33.6 available, DISK: using 117.4 GB with 465.0 available
2022-05-12 09:18:13.025 [WRN] SYNC: Received done peer message for unknown peer 127.0.0.1:57640 (inbound)

getblocktemplate: (block rewards are missing)

DxPool reported that blocks mined using lbcd are missing block rewards

https://explorer.lbry.com/tx/60c09509a9382d2a2314f7fe1f697e07d2aa9af657a291dd351782a0933ca272

The pool software might be using coinbasevalue to construct the coinbase transaction, but the lbcd does not return .coinbasevaklue when the "capabilities": ["coinbasetxn"], is specified.

# lbrycrd
lbcctl --notls -s 18.221.146.233 getblocktemplate '{"rules": ["segwit"]}' | jq .coinbasevalue
23026191340

# lbrycrd
lbcctl --notls -s 18.221.146.233 getblocktemplate '{"capabilities": ["coinbasetxn"],"rules": ["segwit"]}' | jq .coinbasevalue
23025543745

# lbcd
lbcctl getblocktemplate '{"rules": ["segwit"]}' | jq .coinbasevalue
23018485170

# lbcd
lbcctl  getblocktemplate '{"capabilities": ["coinbasetxn"],"rules": ["segwit"]}' | jq .coinbasevalue
null

`invalidateblock` goes back one block at a time, and doesn't reorg properly

For example,

100 -> 101 -> 102 -> 103  (main chain)
     \ 101a (side chain)
  1. invalidate one block at a time from the tip works.
$ getbestblock
{
  hash: HASH_OF_103
  height: 103
}

$ invalidateblock HASH_OF_103
$ invalidateblock HASH_OF_102

$ getbestblock
{
  hash: HASH_OF_101
  height: 101
}
  1. However, even if we invalidate block 101, the main chain doesn't reorg properly to block 101a
$ invalidateblock HASH_OF_101 
$ getbestblock
{
  hash: HASH_OF_101a
  height: 101a
}
$ getblock HASH_OF_101a
block HASH_OF_101a is not in the main chain
  1. invalidate more than one block at a time cause lbcd goes rogue. Starting to exhaust CPU and memory.
$ getbestblock
{
  hash: HASH_OF_103
  height: 103
}

$ invalidateblock HASH_OF_101
(lbcd goes rogue...)

Bring `signrawtransactionwithkey` up to date

Currently unimplemented.

signrawtransaction has been obsoleted in favor of signrawtransactionwithwallet and signrawtransactionwithkey on bitcoin core, since v0.18.0.

We should support signrawtransactionwithkey in lbcd, and implement signrawtransactionwithwallet in lbcwallet

`submitblock` reject blocks due to missing witness in coinbase.

This only happens if the blocks contain any segwit transactions.

2022-08-06 17:47:34.657 [INF] RPCS: Rejected block efdddd30ac5679011ce90efe74a382f1865ef2211a941ba08de8c2a922545126 via submitblock: the coinbase transaction has 0 items in its witness stack when only one is allowed. Height: 1204880
2022-08-06 17:48:00.351 [INF] RPCS: Rejected block eae65b6c2e2ff032452b3d4d05713b774d47096599fada63f5a7d5b69a6aaf46 via submitblock: the coinbase transaction has 0 items in its witness stack when only one is allowed. Height: 1204880

lbcd checks the presence of witness_commitment in the coinbase.TxOut, and asserts the dummy witness (32 bytes of 0s) must also presented in the coinbase.TxIn[0].

Bring `getnetworkinfo` up to date

Bring gtnetworkinfo up to date (v0.23)

On lbcd:

{
  "version": 0,
  "subversion": "LBRY.GO:0.0.0-local.0+5f7b1f1b4f2ebe85c7a41b51ad1f030701c0bb66/",
  "protocolversion": 70013,
  "localservices": "SFNodeNetwork|SFNodeBloom|SFNodeWitness|SFNodeCF",
  "localrelay": true,
  "timeoffset": 0,
  "connections": 8,
  "networkactive": true,
  "networks": [
    {
      "name": "ipv4",
      "limited": false,
      "reachable": false,
      "proxy": "",
      "proxy_randomize_credentials": false
    },
    {
      "name": "ipv6",
      "limited": false,
      "reachable": false,
      "proxy": "",
      "proxy_randomize_credentials": false
    },
    {
      "name": "onion",
      "limited": false,
      "reachable": false,
      "proxy": "",
      "proxy_randomize_credentials": false
    }
  ],
  "relayfee": 0.00001,
  "incrementalfee": 0.00001,
  "localaddresses": null,
  "warnings": ""
}

On lbrycrd (0.17 based):

{
  "version": 170303,
  "subversion": "/LBRY:0.17.3.3/",
  "protocolversion": 70015,
  "localservices": "000000000000040d",
  "localrelay": true,
  "timeoffset": 0,
  "networkactive": true,
  "connections": 8,
  "networks": [
    {
      "name": "ipv4",
      "limited": false,
      "reachable": true,
      "proxy": "",
      "proxy_randomize_credentials": false
    },
    {
      "name": "ipv6",
      "limited": false,
      "reachable": true,
      "proxy": "",
      "proxy_randomize_credentials": false
    },
    {
      "name": "onion",
      "limited": true,
      "reachable": false,
      "proxy": "",
      "proxy_randomize_credentials": false
    }
  ],
  "relayfee": 0.00001000,
  "incrementalfee": 0.00001000,
  "localaddresses": [],
  "warnings": ""
}

Bring `getblockheader` up to date

Missing chainwork, mediantime, and nTx attributes.

lbcctl getblockheader `lbcctl getblockhash 1000000` 1

On lbcd:

{
  "hash": "066d89a69aab2c1e3cb805aa4b2d1526d54758db8b657fa6ce22240afddb80fc",
  "confirmations": 176917,
  "height": 1000000,
  "version": 536870912,
  "versionHex": "20000000",
  "merkleroot": "57d5e9ee479f8568aa93fd438cbcffb742a2c9b9346fcd4df821d7987f60b00d",
  "time": 1627051164,
  "nonce": 74682161,
  "bits": "1a015eab",
  "difficulty": 802670066349.9366,
  "previousblockhash": "e13c26bf391ec0388ba7c530d18e224a2fa6416717d36befe11d6d46e5f37ca1",
  "nextblockhash": "cdfe317ad478ca72d9085bfe8d5ecfdf7e75a8cc0c2d14e66ba784e601730908"
}

On lbrycrd:

{
  "hash": "066d89a69aab2c1e3cb805aa4b2d1526d54758db8b657fa6ce22240afddb80fc",
  "confirmations": 176918,
  "height": 1000000,
  "version": 536870912,
  "versionHex": "20000000",
  "merkleroot": "57d5e9ee479f8568aa93fd438cbcffb742a2c9b9346fcd4df821d7987f60b00d",
  "nameclaimroot": "3dba16ea5516d36b7a2179697a8c99e28edac43b48609c809db95143c274b6a5",
  "time": 1627051164,
  "mediantime": 1627050190,
  "nonce": 74682161,
  "bits": "1a015eab",
  "difficulty": 802670066349.9366,
  "chainwork": "000000000000000000000000000000000000000000000565a6d2dac150305053",
  "nTx": 76,
  "previousblockhash": "e13c26bf391ec0388ba7c530d18e224a2fa6416717d36befe11d6d46e5f37ca1",
  "nextblockhash": "cdfe317ad478ca72d9085bfe8d5ecfdf7e75a8cc0c2d14e66ba784e601730908"
}

Miners rejected while mining non 'LBC' symbol

For debugging and development purpose, we created another Symbol (LBCR) for regtest, which duplicates most of the settings of LBC. However, blocks submit from miners keep being rejected by Yiimp.

Need to investigate if any other settings are missin for the regtest Coin.

Bring `createrawtransaction` up to date

Known issues:

  • doesn't support replaceable
  • doesn't take non-address data in the 2nd parameter.
 lbcctl createrawtransaction '[{"txid": "fd967aa8217fe948cda46b58eb04a7d9af618dc31dc91fbdcde5cbf4f6bf48c4", "vout": 0}]' '{"data": "aabbccdd", "bEQbGgnLQJmmcXAtSBxzNzvUAb5DvRyM4y": 1.0}'
 
createrawtransaction command: parameter #2 'amounts' must be valid JSON which unsmarshals to a map[string]float64 (code: ErrInvalidType)
Usage:
  createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)

Latest spec:

createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )

...

`txscript.ParsePkScript(scriptBytes)` returns "unsupported script type"

For example, transaction 5dda81f42196d2647a173b008d729cf778d3f609adf84610837f039c2f8e88ba

 $ lbcctl getrawtransaction 5dda81f42196d2647a173b008d729cf778d3f609adf84610837f039c2f8e88ba 1

{
  "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100e1f505000000002321024ca653fc094c95aa409430caf2eee08fa6e5fbbe78431e0ec9e7cd80193d98f9ac00000000",
  "txid": "5dda81f42196d2647a173b008d729cf778d3f609adf84610837f039c2f8e88ba",
  "hash": "5dda81f42196d2647a173b008d729cf778d3f609adf84610837f039c2f8e88ba",
  "size": 98,
  "vsize": 98,
  "weight": 392,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "510101",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 1,
      "n": 0,
      "scriptPubKey": {
        "asm": "024ca653fc094c95aa409430caf2eee08fa6e5fbbe78431e0ec9e7cd80193d98f9 OP_CHECKSIG",
        "hex": "21024ca653fc094c95aa409430caf2eee08fa6e5fbbe78431e0ec9e7cd80193d98f9ac",
        "reqSigs": 1,
        "type": "pubkey",
        "subtype": "",
        "isclaim": false,
        "issupport": false,
        "addresses": [
          "bZi1WEjGtsdAwuZTnNNTCAZLxhHkiHec4m"
        ]
      }
    }
  ],
  "blockhash": "decb9e2cca03a419fd9cca0cb2b1d5ad11b088f22f8f38556d93ac4358b86c24",
  "confirmations": 1097697,
  "time": 1466646588,
  "blocktime": 1466646588
}

Decoding in code:

    outputScript := "21024ca653fc094c95aa409430caf2eee08fa6e5fbbe78431e0ec9e7cd80193d98f9ac"
    scriptBytes, _ := hex.DecodeString(outputScript)
    pk, err := txscript.ParsePkScript(scriptBytes)
unsupported script type

Integration with Yiimp

Integration with Pool software - Yiimp

  • 1. Stratum seems have issues connecting to lbcd/lbcwallet via TLS

  • 2. lbcd does not support blocknotify as a builtin function.

  • 3. Stratum complains about Lbry error getblocktemplate

Integration with Block DX

Track lbcd and lbcwallet integration with Block DX, a decentralized exchange.

This project is proposed and initiated by @kodxana
Most required RPCs seem to be supported in lbcd/lbcwallet with few needs to be investigate.

[x] createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)
[x] decoderawtransaction "hextx"
[x] getblock "hash" (verbosity=1)
[x] getblockchaininfo - works but requires lbcwallet running
[x] getnetworkinfo - works but requires lbcwallet running
[x] getblockhash index
[x] getnewaddress - works but requires lbcwallet running
[x] getrawmempool - works but requires lbcwallet running
[x] getrawtransaction "txid" (verbose=false)
[x] gettransaction "txid" (includewatchonly=false)
[x] gettxout "txid" vout (includemempool=true)
[ ] listunspent - works but requires lbcwallet running
[x] sendrawtransaction "hextx" ({"value":value})
[x] signmessage "address" "message"
[x] signrawtransactionwithwallet "rawtx"
[x] signrawtransaction "rawtx" ...
[x] verifymessage "address" "signature" "message"

Extend `lbcblocknotify` to support custom command and multiple destinations.

So far, the users of the lbcdblocknotify programs are predominantly mining pools. For reliability, some pools have multiple instances of backend and frontend services that all act upon the notification. In this case, users have to set up multiple instances of lbcdblocknotify

It is desired to have multiple subscribers for the notification where each of them can customize their command and end points.

Bring `getpeerinfo` up to date

The latest spec (v22.0.0) has updated with quite a lot attributes. We should at least bring lbcd to match lbrycrd, which is based on v0.17.0.

On lbcd:

  {
    "id": 106,
    "addr": "118.93.55.42:9246",
    "addrlocal": "192.168.86.242:61671",
    "services": "00001037",
    "relaytxes": true,
    "lastsend": 1655326305,
    "lastrecv": 1655326304,
    "bytessent": 560414,
    "bytesrecv": 1373028,
    "conntime": 1655311849,
    "timeoffset": 0,
    "pingtime": 165848,
    "version": 70015,
    "subver": "/LBRY:0.17.4.6/",
    "inbound": false,
    "startingheight": 1176898,
    "currentheight": 1176989,
    "banscore": 0,
    "feefilter": 1000,
    "syncnode": false
  },

On lbrycrd:

 {
    "id": 617,
    "addr": "15.235.15.215:9246",
    "addrlocal": "71.38.8.245:62719",
    "addrbind": "192.168.86.242:62719",
    "services": "000000000000004d",
    "relaytxes": true,
    "lastsend": 1655326388,
    "lastrecv": 1655326391,
    "bytessent": 305318,
    "bytesrecv": 873263,
    "conntime": 1655318051,
    "timeoffset": 0,
    "pingtime": 0.079597,
    "minping": 0.078185,
    "version": 70013,
    "subver": "/btcwire:0.5.0/LBRY.GO:0.22.200(Pascals Wager)/",
    "inbound": false,
    "addnode": false,
    "startingheight": 1176941,
    "banscore": 0,
    "synced_headers": 1176994,
    "synced_blocks": 1176994,
    "inflight": [],
    "whitelisted": false,
    "bytessent_per_msg": {
      "addr": 55,
      "feefilter": 32,
      "getaddr": 24,
      "getdata": 28154,
      "getheaders": 1085,
      "inv": 195918,
      "ping": 2240,
      "pong": 2208,
      "sendheaders": 24,
      "tx": 75429,
      "verack": 24,
      "version": 125
    },
    "bytesrecv_per_msg": {
      "addr": 7617,
      "getblocks": 50995,
      "getdata": 7929,
      "headers": 7452,
      "inv": 233643,
      "notfound": 2353,
      "ping": 2208,
      "pong": 2240,
      "tx": 558644,
      "verack": 24,
      "version": 158
    }

Latest spec:

[                                     (json array)
  {                                   (json object)
    "id" : n,                         (numeric) Peer index
    "addr" : "str",                   (string) (host:port) The IP address and port of the peer
    "addrbind" : "str",               (string) (ip:port) Bind address of the connection to the peer
    "addrlocal" : "str",              (string) (ip:port) Local address as reported by the peer
    "network" : "str",                (string) Network (ipv4, ipv6, onion, i2p, not_publicly_routable)
    "mapped_as" : n,                  (numeric) The AS in the BGP route to the peer used for diversifying
                                      peer selection (only available if the asmap config flag is set)
    "services" : "hex",               (string) The services offered
    "servicesnames" : [               (json array) the services offered, in human-readable form
      "str",                          (string) the service name if it is recognised
      ...
    ],
    "relaytxes" : true|false,         (boolean) Whether peer has asked us to relay transactions to it
    "lastsend" : xxx,                 (numeric) The UNIX epoch time of the last send
    "lastrecv" : xxx,                 (numeric) The UNIX epoch time of the last receive
    "last_transaction" : xxx,         (numeric) The UNIX epoch time of the last valid transaction received from this peer
    "last_block" : xxx,               (numeric) The UNIX epoch time of the last block received from this peer
    "bytessent" : n,                  (numeric) The total bytes sent
    "bytesrecv" : n,                  (numeric) The total bytes received
    "conntime" : xxx,                 (numeric) The UNIX epoch time of the connection
    "timeoffset" : n,                 (numeric) The time offset in seconds
    "pingtime" : n,                   (numeric) ping time (if available)
    "minping" : n,                    (numeric) minimum observed ping time (if any at all)
    "pingwait" : n,                   (numeric) ping wait (if non-zero)
    "version" : n,                    (numeric) The peer version, such as 70001
    "subver" : "str",                 (string) The string version
    "inbound" : true|false,           (boolean) Inbound (true) or Outbound (false)
    "bip152_hb_to" : true|false,      (boolean) Whether we selected peer as (compact blocks) high-bandwidth peer
    "bip152_hb_from" : true|false,    (boolean) Whether peer selected us as (compact blocks) high-bandwidth peer
    "startingheight" : n,             (numeric) The starting height (block) of the peer
    "synced_headers" : n,             (numeric) The last header we have in common with this peer
    "synced_blocks" : n,              (numeric) The last block we have in common with this peer
    "inflight" : [                    (json array)
      n,                              (numeric) The heights of blocks we're currently asking from this peer
      ...
    ],
    "permissions" : [                 (json array) Any special permissions that have been granted to this peer
      "str",                          (string) bloomfilter (allow requesting BIP37 filtered blocks and transactions),
                                      noban (do not ban for misbehavior; implies download),
                                      forcerelay (relay transactions that are already in the mempool; implies relay),
                                      relay (relay even in -blocksonly mode, and unlimited transaction announcements),
                                      mempool (allow requesting BIP35 mempool contents),
                                      download (allow getheaders during IBD, no disconnect after maxuploadtarget limit),
                                      addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info).
                                      
      ...
    ],
    "minfeefilter" : n,               (numeric) The minimum fee rate for transactions this peer accepts
    "bytessent_per_msg" : {           (json object)
      "msg" : n,                      (numeric) The total bytes sent aggregated by message type
                                      When a message type is not listed in this json object, the bytes sent are 0.
                                      Only known message types can appear as keys in the object.
      ...
    },
    "bytesrecv_per_msg" : {           (json object)
      "msg" : n,                      (numeric) The total bytes received aggregated by message type
                                      When a message type is not listed in this json object, the bytes received are 0.
                                      Only known message types can appear as keys in the object and all bytes received
                                      of unknown message types are listed under '*other*'.
      ...
    },
    "connection_type" : "str"         (string) Type of connection: 
                                      outbound-full-relay (default automatic connections),
                                      block-relay-only (does not relay transactions or addresses),
                                      inbound (initiated by the peer),
                                      manual (added via addnode RPC or -addnode/-connect configuration options),
                                      addr-fetch (short-lived automatic connection for soliciting addresses),
                                      feeler (short-lived automatic connection for testing addresses).
                                      Please note this output is unlikely to be stable in upcoming releases as we iterate to
                                      best capture connection behaviors.
  },
  ...
]

yiimp/stratum report "LBRY Credits #block not reporting"

15:56:30: LBRY Credits 1198462 not reporting
16:12:24: LBRY Credits 1198470 not reporting
16:13:28: LBRY Credits 1198471 not reporting
16:16:17: LBRY Credits 1198472 not reporting
16:18:45: LBRY Credits 1198473 not reporting
16:19:27: LBRY Credits 1198474 not reporting

yimmp was still able to conducting the mining cycle:

  1. getblocktemplate()
  2. distribute jobs to miners
  3. submiteblock() back to the lbcd

But the accepted blocks () was not reported and entered into yimmp database, and requires operator's intervene.

Claimtire build taking too much ram and causing a crash

I'm trying to run a full lbcd node and synced up to height ~1 000 000 but now when i'm trying to run lbcd again i can't get past
height ~700 000 in the initial rebuilding of the claimtrie with it eating all my 16GB of ram + 16GB of swap and crashing.

The ram usage goes up very rapidly from around height 600 000.
Screenshot from 2023-07-07 22-26-05

Screenshot from 2023-07-07 22-26-48

Considering the blockchain is 1 400 000 blocks high at this moment how much ram is needed to run a full lbcd node ?
The readme says 8GB are needed but its already taking 32GB at height ~700 000 and i'm guessing the remaining blocks contain way more claims than the first.

I know the readme says that ram usage may increase over time but at this point if this is the expected usage i think the baseline should be updated to reflect more accurately the current state of things.

The default `lbcd.conf` is not generated.

lbcd generates the default lbcd.conf using the sample-lbcd.conf sitting next to the lbcd binary.

If it doesn't find it, the default lbcd.conf won't be generated.

Solutions:

  1. Update the CI script to bundle the sample-lbcd.conf in the release tarball.
  2. Embed the sample-lcbd.conf using [go embedded feature] (https://pkg.go.dev/embed)

The 2) is preferred.

Bring `getblockchaininfo` up to date

Bring getblockchaininfo up to date (v0.23)

On lbcd:

{
  "chain": "mainnet",
  "blocks": 1174511,
  "headers": 1174511,
  "bestblockhash": "bb9a8030f84f710b88a91521e80289facb4924eb24e08702757e1294997452c6",
  "difficulty": 1369713051994.9846,
  "mediantime": 1654923545,
  "pruned": false,
  "bip9_softforks": {
    "csv": {
      "status": "active",
      "bit": 0,
      "startTime": 0,
      "start_time": 1462060800,
      "timeout": 1493596800,
      "since": 200000
    },
    "dummy": {
      "status": "failed",
      "bit": 28,
      "startTime": 0,
      "start_time": 1199145601,
      "timeout": 1230767999,
      "since": 0
    },
    "segwit": {
      "status": "active",
      "bit": 1,
      "startTime": 0,
      "start_time": 1547942400,
      "timeout": 1548288000,
      "since": 680770
    },
    "taproot": {
      "status": "failed",
      "bit": 0,
      "startTime": 0,
      "start_time": 0,
      "timeout": 0,
      "since": 0
    }
  }
}

On lbrycrd (0.17 based):

{
  "chain": "lbrycrd",
  "blocks": 1174511,
  "headers": 1174511,
  "bestblockhash": "bb9a8030f84f710b88a91521e80289facb4924eb24e08702757e1294997452c6",
  "difficulty": 1369713051994.985,
  "mediantime": 1654923545,
  "verificationprogress": 0.999194946520285,
  "initialblockdownload": false,
  "chainwork": "000000000000000000000000000000000000000000000970cda1e06046741a5e",
  "size_on_disk": 90879066566,
  "pruned": false,
  "softforks": [
    {
      "id": "bip34",
      "version": 2,
      "reject": {
        "status": true
      }
    },
    {
      "id": "bip66",
      "version": 3,
      "reject": {
        "status": true
      }
    },
    {
      "id": "bip65",
      "version": 4,
      "reject": {
        "status": true
      }
    }
  ],
  "bip9_softforks": {
    "csv": {
      "status": "active",
      "startTime": 1462060800,
      "timeout": 1493596800,
      "since": 6048
    },
    "segwit": {
      "status": "active",
      "startTime": 1547942400,
      "timeout": 1548288000,
      "since": 508032
    }
  },
  "warnings": ""
}

Implement `getblockstat`RPC

This is requested by DxPool for the totalfees to calculate revenue.

A pending PR for btcd has implemented it.

Need to merge and test it though.

Bring `getmininginfo` up to date

Update the the testnet boolean attribute to chain string for network name.

On lbcd:

lbcctl getmininginfo
{
  "blocks": 1176991,
  "currentblocksize": 99937,
  "currentblockweight": 399640,
  "currentblocktx": 124,
  "difficulty": 1873348963350.1497,
  "errors": "",
  "generate": false,
  "genproclimit": 16,
  "hashespersec": 0,
  "networkhashps": 543153148851407,
  "pooledtx": 212,
  "testnet": false
}

Latest spec:

{                              (json object)
  "blocks" : n,                (numeric) The current block
  "currentblockweight" : n,    (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)
  "currentblocktx" : n,        (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)
  "difficulty" : n,            (numeric) The current difficulty
  "networkhashps" : n,         (numeric) The network hashes per second
  "pooledtx" : n,              (numeric) The size of the mempool
  "chain" : "str",             (string) current network name (main, test, signet, regtest)
  "warnings" : "str"           (string) any network and blockchain warnings
}

Bring `getblock` up to date

Missing chainwork and mediantime

On lbcd:

lbcctl getblock ac280c2a68c57707cc1fedbd025782c76cc2679550aa18cc5bd6e3f64c2a2769
{
  "hash": "ac280c2a68c57707cc1fedbd025782c76cc2679550aa18cc5bd6e3f64c2a2769",
  "confirmations": 1,
  "strippedsize": 16191,
  "size": 16227,
  "weight": 64800,
  "height": 1172332,
  "version": 536870912,
  "versionHex": "20000000",
  "merkleroot": "b3717572eb82f625a1de2735fbb119802032d07b59a2c84d25c5d5bcb4a69128",
  "time": 1654577506,
  "nonce": 3245888345,
  "bits": "1a009cca",
  "difficulty": 1795218858097.069,
  "previousblockhash": "9ee97ed1dbaf34fbf40d755ccb9a23b3074e61b1572a8135397a9f6514d741ca",
  "nameclaimroot": "1c6a4517e9254d0becdfc1dd5257b8c66b58899618e9305f1fab57a7054c12cd",
  "nTx": 33,
  "tx": [
    "07c8b6aa16d59f184e6aea71e613b08be52182869b9fdeba422a0dbf47411383",
    "1f0eeaa0480639805849724e835be04f1e041f73ed1f10caceb4db70c7403876",
    "0a999db30bfa1116646347dc8a6c1baf62ae1998c63640f48c33b02117fc1412",
    ...
  ]
}

On lbrycrd:

lbcctl --notls -s $LBRYCRD_NODE getblock ac280c2a68c57707cc1fedbd025782c76cc2679550aa18cc5bd6e3f64c2a2769
{
  "hash": "ac280c2a68c57707cc1fedbd025782c76cc2679550aa18cc5bd6e3f64c2a2769",
  "confirmations": 1,
  "strippedsize": 16191,
  "size": 16227,
  "weight": 64800,
  "height": 1172332,
  "version": 536870912,
  "versionHex": "20000000",
  "merkleroot": "b3717572eb82f625a1de2735fbb119802032d07b59a2c84d25c5d5bcb4a69128",
  "time": 1654577506,
  "nonce": 3245888345,
  "bits": "1a009cca",
  "difficulty": 1795218858097.069,
  "previousblockhash": "9ee97ed1dbaf34fbf40d755ccb9a23b3074e61b1572a8135397a9f6514d741ca",
  "nameclaimroot": "1c6a4517e9254d0becdfc1dd5257b8c66b58899618e9305f1fab57a7054c12cd",
  "nTx": 33,
  "tx": [
    "07c8b6aa16d59f184e6aea71e613b08be52182869b9fdeba422a0dbf47411383",
    "1f0eeaa0480639805849724e835be04f1e041f73ed1f10caceb4db70c7403876",
    "0a999db30bfa1116646347dc8a6c1baf62ae1998c63640f48c33b02117fc1412",
    ...

  ],
  "mediantime": 1654577056,
  "chainwork": "000000000000000000000000000000000000000000000964a8366f9822316ea1"
}

Make `getblock` return orphan blocks with `confirmation: -1`

Currently, orphan blocks and transactions are kept in the block database, but not available for query.

 lbcctl getblock 09555f547a4065b36561fbc3887023b3c97c592f6b77c5d9cb8adfbd0095eea8

-32603: block 09555f547a4065b36561fbc3887023b3c97c592f6b77c5d9cb8adfbd0095eea8 is not in the main chain

Some software like yiimp relies on this information to handle reorgs properly.

I don't have a orphan block at hand, but got a sample from other bitcoind-alike coin:

$ ./bin/DGB-cli getblock 4ad54d7ac4b421188085f029abd65ede86e94e83f73f35d69366c7cef9cecae7
{
  "hash": "4ad54d7ac4b421188085f029abd65ede86e94e83f73f35d69366c7cef9cecae7",
  "confirmations": -1,
  "strippedsize": 194,
  "size": 194,
  "weight": 776,
  "height": 15673117,
  "version": 536872962,
  "versionHex": "20000802",
  "pow_algo_id": 4,
  "pow_algo": "qubit",
  "pow_hash": "00000000000004b4de8617ec23ae5b41414c447e21bd28f96372d92e7cc25f04",
  "merkleroot": "4fc2feb6643fb003641979cd44fe55e6d1de6925d98465eb96092e4a6230d8b8",
  "tx": [
    "4fc2feb6643fb003641979cd44fe55e6d1de6925d98465eb96092e4a6230d8b8"
  ],
  "time": 1661833543,
  "mediantime": 1661833518,
  "nonce": 1676480887,
  "bits": "1a15fca8",
  "difficulty": 763042.1132930262,
  "chainwork": "0000000000000000000000000000000000000000000fcce720fc57df108155cc",
  "nTx": 1,
  "previousblockhash": "e81750620337f26d3c05cf0e064b4d3e2da6b98a6c05320b2c42477582d0ec09"
}

Making the orphan blocks returned with confirmation: -1 should make it compatible.

Support starting `lbcd` with snapshot

To help new nodes catch up faster without syncing blocks from scratch, we publish snapshots compressed in zstd format.

Some users requested a convenient way to start lbcd with the snapshot without manually downloading and uncompress the snapshot. This is handy for automated / integrated setup environment.

This can be done with:

  1. a wrapper script which downloads and uncompresses the snapshot before starting lbcd.
  2. --snapshot cli flag, which takes a file or url.
    Go has zstd package to do this.

Either implementation should support:

  1. Download a snapshot from a URL
    Uncompress from a downloaded snapshot

  2. Download and uncompress on the fly, for example:

curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1178238_v0.22.100_2022-06-17.tar.zst | zstd -d | tar xf - -C ${LBCD_DIR}

Note: 2) support of --snapshot is preferred so we don't require installing zstd packages

Bring `mempoolinfo` up to date

On lbcd

{
  "size": 76,
  "bytes": 54793
}

On lbrycrd:

{
  "size": 157,
  "bytes": 127988,
  "usage": 267040,
  "maxmempool": 300000000,
  "mempoolminfee": 0.00001000,
  "minrelaytxfee": 0.00001000
}

Latest spec:

{                            (json object)
  "loaded" : true|false,     (boolean) True if the mempool is fully loaded
  "size" : n,                (numeric) Current tx count
  "bytes" : n,               (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted
  "usage" : n,               (numeric) Total memory usage for the mempool
  "total_fee" : n,           (numeric) Total fees for the mempool in BTC, ignoring modified fees through prioritizetransaction
  "maxmempool" : n,          (numeric) Maximum memory usage for the mempool
  "mempoolminfee" : n,       (numeric) Minimum fee rate in BTC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee
  "minrelaytxfee" : n,       (numeric) Current minimum relay fee for transactions
  "unbroadcastcount" : n     (numeric) Current number of transactions that haven't passed initial broadcast yet
}

Bring `getrawmempool` up to date

ancestor* descendant* attributes are currently mocked with the transaction itself, not from the actual ancestors/descendants.

$ lbrycrd-cli getrawmempool true > lbrycrd-getrawmempool.json

 "016c84d9bf2d1d6e134b513fc03878847ae2a8fe310aea0a399d8518202ddefa": {
    "fees": {
      "base": 0.00114100,
      "modified": 0.00114100,
      "ancestor": 0.00114100,
      "descendant": 0.00114100
    },
    "size": 2259,
    "fee": 0.00114100,
    "modifiedfee": 0.00114100,
    "time": 1644594445,
    "height": 1110043,
    "descendantcount": 1,
    "descendantsize": 2259,
    "descendantfees": 114100,
    "ancestorcount": 1,
    "ancestorsize": 2259,
    "ancestorfees": 114100,
    "wtxid": "016c84d9bf2d1d6e134b513fc03878847ae2a8fe310aea0a399d8518202ddefa",
    "depends": [
    ],
    "spentby": [
    ]
  },
...
$  lbcctl getrawmempool true > lbcd-getrawmempool.json

  "016c84d9bf2d1d6e134b513fc03878847ae2a8fe310aea0a399d8518202ddefa": {
    "size": 2259,
    "vsize": 2259,
    "weight": 9036,
    "fee": 0.001141,
    "time": 1644594446,
    "height": 1110043,
    "startingpriority": 55887613.765151516,
    "currentpriority": 55892328.428030305,
    "depends": []
  },
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.