A blockchain implementation in Go, as described in these articles:
jeiwan / blockchain_go Goto Github PK
View Code? Open in Web Editor NEWA simplified blockchain implementation in Golang
A simplified blockchain implementation in Golang
A blockchain implementation in Go, as described in these articles:
Merkle tree's length should be 2^n, not 2*n.
For example, when there are 5 leaf nodes, it should be append to a length of eight not six.
Line 138 in bf64f33
When I try to run this code and print all the transactions' information, I found that Vout is wrong.
I think outIdx should be replaced by out.Value.
go run main.go
# command-line-arguments
./main.go:4:9: undefined: CLI
Step to reproduce
loop until error occurs 'panic: ERROR: Address is not valid'
that wont take too long.
Indexes of TXOutput is different in TXOutputs and Transaction, use index in utxo to initialize inputs of transaction then put it into block is wrong.
I translated your article series to korean.
Again, thank you for great article.
Hi!In the 4th part,If someone transfers money to himself,his account balance will be double。
if out.CanBeUnlockedWith(address) {
unspentTXs = append(unspentTXs, *tx)
}
There is a “break” missing here!This statement is in the blockchain.go。
Thank you very much for your tutorial and please note this little bug~
URL: https://github.com/Gelembjuk/democoin
I am going to investigate this project.
Hi there
Thanks for your great article. I just wanted to know the differences between fmt.Sprintf("%s", []byte)
and string([]byte[:])
? Are there any advantages in one way (you're using the first mostly)?
Many thanks!
Timon
In branch part_5, blockchain.go#L109:
Line 109 in 201e7a1
The second judgment condition accumulated < amount
is not necessary. It only works when amount <= 0
, In this case, we should check the value of amount
at the beginning of the function.
func (bc *Blockchain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
unspentOutputs := make(map[string][]int)
accumulated := 0
// Maybe we should check “amount” at the beginning of the function.
if (amount <= 0){
return accumulated,unspentOutputs
}
unspentTXs := bc.FindUnspentTransactions(pubKeyHash)
Work:
for _, tx := range unspentTXs {
txID := hex.EncodeToString(tx.ID)
for outIdx, out := range tx.Vout {
if out.IsLockedWithKey(pubKeyHash) { // Delete “&& accumulated < amount”
accumulated += out.Value
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
if accumulated >= amount {
break Work
}
}
}
}
return accumulated, unspentOutputs
}
If you try to send transaction with mineNow = false from same wallet (address) 2 times, you got 2 transactions with same transaction hash, because NewUTXOTransaction will create identical Transaction structs.
My solution works with adding some salt:
// Hash returns the hash of the Transaction
func (tx *Transaction) Hash() []byte {
var hash [32]byte
txCopy := *tx
txCopy.ID = []byte{}
salt := make([]byte, 32)
_, err := io.ReadFull(rand.Reader, salt)
if err != nil {
fmt.Printf("ERROR: Creating salt failed: %s\n", err)
}
data := txCopy.Serialize()
data = append(data, salt...)
hash = sha256.Sum256(data)
return hash[:]
}
When creating a new blockchain, the current implementation of ValidateAddress
panics:
$ blockchain_go createblockchain -address $NODE_ID
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
main.ValidateAddress(0x7ffeefbff78c, 0x4, 0xc0000a55b0)
/Users/go-crypto/wallet.go:56 +0x202
main.(*CLI).createBlockchain(0xc0000c5f88, 0x7ffeefbff78c, 0x4, 0xc00001a048, 0x4)
/Users/go-crypto/cli_createblockchain.go:9 +0x3f
main.(*CLI).Run(0xc0000c5f88)
/Users/go-crypto/cli.go:117 +0x5ce
main.main()
/Users/go-crypto/main.go:5 +0x2b
where
$ echo $NODE_ID
3000
Is there a potential quick fix here by changing:
// wallet.go
const addressChecksumLen = 4
?
Hi, I’m new to the blockchain field and I’ll practice your lessons.
https://jeiwan.cc/posts/building-blockchain-in-go-part-3/
While writing blockchhain on your tutorials, I ran into a problem. The program comes with the first error. After downloading your project from the github, I confronted the same problem, the program ends without letting you add new blocks. Because I ask for help, could you explain what the problem is?
Code:
func (cli *CLI) validateArgs() {
if len(os.Args) < 2 {
cli.printUsage()
os.Exit(1)
}
}
Output:
Usage:
addblock -data BLOCK_DATA - add a block to the blockchain
printchain - print all the blocks of the blockchain
Process finished with exit code 1
I apologize for the trouble and hope for an answer
When I send transaction without -mine flag, so when I wait for the miner node to mine, I get an error on FindTransaction() method.
goroutine 24 [running]:
log.Panic(0xc000125750, 0x1, 0x1)
/usr/local/go/src/log/log.go:326 +0xc0
blockchain/main/blockchain.Handle(0x9f4900, 0xc005512af0)
/home/melianor/go/src/blockchain/main/blockchain/block.go:70 +0x64
blockchain/main/blockchain.(*BlockChain).VerifyTransaction(0xc00016c520, 0xc0054f8280, 0xc005528140)
/home/melianor/go/src/blockchain/main/blockchain/blockchain.go:371 +0x39e
blockchain/main/network.MineTx(0xc00016c520)
/home/melianor/go/src/blockchain/main/network/network.go:361 +0x197
blockchain/main/network.HandleTx(0xc00550e600, 0x24a, 0x600, 0xc00016c520)
/home/melianor/go/src/blockchain/main/network/network.go:350 +0x606
blockchain/main/network.HandleConnection(0x9fa600, 0xc00000e670, 0xc00016c520)
/home/melianor/go/src/blockchain/main/network/network.go:448 +0x2d1
created by blockchain/main/network.StartServer
/home/melianor/go/src/blockchain/main/network/network.go:493 +0x2e3
exit status 2
when I send amount on mac os:
$ ./blockchain_go send -from 18LzaPoMWzHb4fozkp1AJeiomjQBSTMshY -to 15qAH88JWPzv7D1cKz4xj63NXse4WDZiGU -amount 1
I received the error:
2018/02/09 15:52:57 sendTx to addr (localhost:3000)
localhost:3000 is not available,err = dial tcp [::1]:3000: getsockopt: connection refused
Success!
what can I do?
The problematic code looks like this:
// NewMerkleTree creates a new Merkle tree from a sequence of data
func NewMerkleTree(data [][]byte) *MerkleTree {
var nodes []MerkleNode
if len(data)%2 != 0 {
data = append(data, data[len(data)-1])
}
for _, datum := range data {
node := NewMerkleNode(nil, nil, datum)
nodes = append(nodes, *node)
}
for i := 0; i < len(data)/2; i++ {
var newLevel []MerkleNode
for j := 0; j < len(nodes); j += 2 {
node := NewMerkleNode(&nodes[j], &nodes[j+1], nil)
newLevel = append(newLevel, *node)
}
nodes = newLevel
}
mTree := MerkleTree{&nodes[0]}
return &mTree
}
Because the count of total level 'k' is equal to [k = log2(S + 1)] , S is the number of "Full Binary Tree" nodes.
Such as, When len(Leaf nodes) = 32, so S = 63 , k = log2(63+1) = 6; Now k is 6, not 32/2!
My code show below:
func NewMerkleTree(data [][]byte) *MerkleTree {
var nodes []MerkleNode
if len(data)%2 != 0 {
data = append(data, data[len(data)-1])
}
for _, datum := range data {
mNode := NewMerkleNode(nil, nil, datum)
nodes = append(nodes, *mNode)
}
TreeNode:
for {
var newLevel []MerkleNode
for j := 0; j < len(nodes); j += 2 {
if len(nodes) == 1 {
break TreeNode
}
node := NewMerkleNode(&nodes[j], &nodes[j+1], nil)
newLevel = append(newLevel, *node)
}
nodes = newLevel
}
mTree := MerkleTree{&nodes[0]}
return &mTree
}
Line 36 in fee9bfd
Please forgive my English is not very good, I want to report a issue when constructs the merkle tree.
I think, the leaves number of merkle tree should be power of 2, not even, or the program will stack overflow.
For example 6, when i = 1, j = 2, the index of nodes[j+1] will be out of bounds.
go run main.go startnode -miner 16yKFXXWEGh1mN5fjfNHNrWS3j5oPvuoni
Starting node maguayo
Mining is on. Address to receive rewards: 16yKFXXWEGh1mN5fjfNHNrWS3j5oPvuoni
2018/01/15 09:53:49 listen tcp: lookup tcp/maguayo: nodename nor servname provided, or not known
panic: listen tcp: lookup tcp/maguayo: nodename nor servname provided, or not known
goroutine 1 [running]:
log.Panic(0xc420049ce0, 0x1, 0x1)
/usr/local/Cellar/go/1.8.3/libexec/src/log/log.go:322 +0xc0
...
I have checked the code for many many time. However, I could not figure out what is going on. Thanks a lot for helping me solve this problem.
I add following code in line206 of server.go to check received block merkle root before Node 3001 accepts it.
fmt.Printf("Merkle root %x\n", block.HashTransactions())
I add following code in line20 of cli_printchain.go to check block merkle root of Node 3000
fmt.Printf("Merkle Root: %x\n", block.HashTransactions())
============ Block 0000a7984f7d50d2ed14d3258929a51968dfc8c72f7e4bf5aa9dfe8259c63 763 ============
Height: 2
Prev. block: 00002a49026d0c09c705656e712454330081cf4b1a34b6a94272b96eaebc9b9d
Merkle Root: 2e9ca5178708cd52921a1e04da0119f2c880a3acbde48587c0111233133e83e5
PoW: true
--- Transaction ee722146dfec6f180caddfffb59c9f91c59283a77b8eb62712bba2b9685b3508 :
Input 0:
TXID:
Out: -1
Signature:
PubKey: 38663663653861313435663431353333393861666534343364666532616133 653635386438343533
Output 0:
Value: 10
Script: 63c894ec2fefbaaaec894330c84d6ac4d9368f32
--- Transaction 15573a2f01c78697da7feabec2addb6d88566df5739107b03569d9a6108264a2 :
Input 0:
TXID: 014d3733ddcac7d8a6ddc8773dd20c5c3a5fa24f00f805b1f7f9463c4c34c7 86
Out: 0
Signature: 7604be74a211bb555d4cb4398c5a03f92f16336ebfd5daded074be2740406d 9379d05f178da575dc3920e0bca6846b0d604fe7091270b3827545cdc6ab713c27
PubKey: 2dd3203343090c26c4f3eec07ed25a81b576e80cce5be3606e0369dfee3a7c 96c03569b60e49033924477b9064ba31e78184f6e116128961dfef5fcfd837ed21
Output 0:
Value: 10
Script: 44106b8010bebd3cd52e6456485b9a1832ffc487
============ Block 00002a49026d0c09c705656e712454330081cf4b1a34b6a94272b96eaebc9 b9d ============
Height: 1
Prev. block: 00002ecf72d5c715045fe2a1df4d4bde31bde6068b3692b6e3b952462d400578
Merkle Root: 86b83927a27e60fb9bc356b698706bbccd7f325b13632d52a7180a2895cd6084
PoW: true
...
Starting node 3001
Received version command
Received inv command
Recevied inventory with 3 block
Received block command
Recevied a new block!
Added block 0000a7984f7d50d2ed14d3258929a51968dfc8c72f7e4bf5aa9dfe8259c63763
Merkle root 1c2feda8be36b4e886b5271866c57be11d447095ec4d09a13932c3933f73d235
Received block command
Recevied a new block!
Added block 00002a49026d0c09c705656e712454330081cf4b1a34b6a94272b96eaebc9b9d
Merkle root 0c83315ca4d85362613b4d46b1509498e6864dcead04fd17409053877c948f1c
Received block command
Recevied a new block!
Added block 00002ecf72d5c715045fe2a1df4d4bde31bde6068b3692b6e3b952462d400578
Merkle root d8247ea3d8f866d55a868ffa8fb0b96d871f1b4cda5f52bfac479af1fbfa79c5
Block: 0000a7984f7d50d2ed14d3258929a51968dfc8c72f7e4bf5aa9dfe8259c63763
NODE_3000: 2e9ca5178708cd52921a1e04da0119f2c880a3acbde48587c0111233133e83e5
NODE_3001: 1c2feda8be36b4e886b5271866c57be11d447095ec4d09a13932c3933f73d235
Block: 00002a49026d0c09c705656e712454330081cf4b1a34b6a94272b96eaebc9b9d
NODE_3000: 86b83927a27e60fb9bc356b698706bbccd7f325b13632d52a7180a2895cd6084
NODE_3001: 0c83315ca4d85362613b4d46b1509498e6864dcead04fd17409053877c948f1c
...
First of all, thank you Ivan for sharing us this project. It's a really great help for us learning the inner workings of blockchain technology. I enjoyed it very much.
I just wondered if there would be a Building Blockchain in Go. Part 8 to implement P2P network. Though I'm hoping so much there would be :)
I was looking for something like this for a while, thanks for taking the time to create this useful resource to learn more about what makes the blockchain work.
Accept BTC tips?
Cheers
when i run the main.go file, it shows ./main.go:8:11 undefined:New NewBlockchain
do you have this problem?
New block minede by NODE_3002.and printchain the PoW is false.
I think a lot. But I did't get the problem.
I'd be appreciate for this if anybody help.
good source
thanks
I am going to design test suite for this project and if anybody has some tests it would be great for start!
Dear Jeiwan,
I try to build your code with GoLand
IDE (Go 1.9.2
) and got the error
`# command-line-arguments
./main.go:4:9: undefined: CLI
Process finished with exit code 2`
How to fix it?
In line 157 blockchain.go, it seems that TXOutputs has never been declared, is it TXOutput[] or I miss something?
Hi. There should be something wrong with your base58 implentation after this commit.
It will cause wallet address decode error like this.
./blockchain_go createblockchain -address 1DU9fP5ZtqjR3MJvHvV7vvWsuZcBFZ2PeG
2017/11/22 02:00:46 ERROR: Address is not valid
panic: ERROR: Address is not valid
If a user has a balance of 2, and now he initiates a transaction with a payment of 2, and then a transaction with a payment of 2 when no block is generated, is there a dual consumption problem?
for b := range input {
if b == 0x00 {
result = append([]byte{b58Alphabet[0]}, result...)
} else {
break
}
}
in this cycle, b is the index of input, not the value, so i think it may be wrong here.
it should be
for _, b := range input {
...
}
both in two functions this file(line26 & line42).
Thanks for the tutorial. I'm working my way through it now.
One suggestion though. Could you reference which new packages you're importing at each stage. I'm following along with the tutorial and building bit-by-bit and I have to keep running the code, after each new section is introduced, waiting for the undefined: XXX
errors and then looking up the Golang docs to find which package I need to import to include XXX
blockchain_go send -from 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR -to 1L8SGeGZsLonjfAvh5hKGcocs1dvJMubvn -amount 6 -mine
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1057338]
goroutine 1 [running]:
main.Wallets.GetWallet(...)
/Users/zhengzhixiong/workspace_go/src/blockchain_go/cli_send.go:24
main.(*CLI).send(0xc420053f70, 0x7ffeefbff6d9, 0x22, 0x7ffeefbff700, 0x22, 0x6, 0xc420018018, 0x4, 0x11ca201)
/Users/zhengzhixiong/workspace_go/src/blockchain_go/cli_send.go:24 +0x1cd
main.(*CLI).Run(0xc4200bbf70)
/Users/zhengzhixiong/workspace_go/src/blockchain_go/cli.go:144 +0x711
main.main()
/Users/zhengzhixiong/workspace_go/src/blockchain_go/main.go:5 +0x2b
zhengzhixiongdeMacBook-Pro-4:blockchain_go zhengzhixiong$
hi, I don't know the usage of startnode -miner . I run these command below:
C:\tools\src\github.com\jeiwan\blockchain_go>blockchain_go.exe startnode -miner 1PLejYY8uACB89KrKnPz2Ea5ggxd5LniSm
Starting node 3000
Mining is on. Address to receive rewards: 1PLejYY8uACB89KrKnPz2Ea5ggxd5LniSm
but then how to go to next setp? can you tell me the next setp?
Hi, I tryed go install in both macOs and Debian, same problem.
`./blockchain_go createblockchain -address 1PEiixXK7E8S7pqkjTiePUnP9jZFBonBR9
2018/01/25 18:08:00 ERROR: Address is not valid
panic: ERROR: Address is not valid
goroutine 1 [running]:
log.Panic(0xc420055dc8, 0x1, 0x1)
/usr/local/go/src/log/log.go:326 +0xc0
main.(*CLI).createBlockchain(0xc420055f70, 0x7fff5fbffc2a, 0x22, 0xc420016048, 0x5)
/Users/simo/go/src/blockchain_go/cli_createblockchain.go:10 +0x169
main.(*CLI).Run(0xc420055f70)
/Users/simo/go/src/blockchain_go/cli.go:119 +0x615
main.main()
/Users/simo/go/src/blockchain_go/main.go:5 +0x2b`
If you run the project in the part_2 there is no end, and keeps printing the hash forever.
Mining the block containing "Genesis Block"
3f22aecfa055d42189abe136137514db35bd852762b9d1129fd8098bc0bc5c45
Thank you for inspiration! I will make Python Port is currently going development here
Could I?
I've successfully changed the data inside db, I thought changes that was done by a node is visible to the other nodes
3000 Central node role,3001 SPV role,3002 miner role。3001 Continue to send payment cost,The balance is not enough to be paid again。
Hi,
I have implemented this repo in PHP
https://github.com/miniyarov/php-blockchain
I have also translated it to Turkish
https://medium.com/@miniyarov/php-ile-blockchain-blokzinciri-yaz%C4%B1yoruz-b%C3%B6l%C3%BCm-1-basit-prototip-fea8e81ed423
Thanks @Jeiwan for inspiring.
============ Block 03336ca7d60ba5344265de897b055fc2472681524a1751679c6ec17dc734ae70 ============
Height: 2
Prev. block: 09d26e7629fb8f5918faf0623351ba1f5740406fe29e6b433522b7441b34958e
PoW: true
--- Transaction e734d0dd763d10f1e4bb175bad312de1de51a6f08e7ddbc18300412f003f4654:
Input 0:
TXID: 598b4e12b0bd16e87f7cdd108a4361c27c147e943fe7742a807dd3d8d0a7f2db
Out: 0
Signature: 9802715ce2c6be6b5893c0ad6e77e13b9d6cf1a798b85e7597665edb297cf1e5f2af34a5c43235276bfd3215e6f3d1bf7e063538cec33d07e0b4e1dfce03e335
PubKey: 7f3310fd561c9d414b9869c31431b649b304cf0177c743c9c3932584e9421102069a563840f3d076070a47c36479f56aa0453451e29e67b3e113c8d86ffa64a8
Output 0:
Value: 2
Script: cf4459389be8f77df9ac2d41bb29e80f5f4120d0
Output 1:
Value: 8
Script: 12facdbb0eb291427b4b9a4745b2553c5e659dc2
--- Transaction 3bb3cd1345d276e8e76345c8aa109089c9f06d37f471f0603e97fd38bdb88905:
Input 0:
TXID: 598b4e12b0bd16e87f7cdd108a4361c27c147e943fe7742a807dd3d8d0a7f2db
Out: 0
Signature: 0dae57ad9c2385a0977a758c4b0fb184a44cdf0558d768653b4b8669a47814c9c0df39a64fe913a8cab653b90a3cbbae2c56c92520da66892d522863e11f31b6
PubKey: 7f3310fd561c9d414b9869c31431b649b304cf0177c743c9c3932584e9421102069a563840f3d076070a47c36479f56aa0453451e29e67b3e113c8d86ffa64a8
Output 0:
Value: 1
Script: c9f24de063058507e8ada37a93b02e8f02218ebf
Output 1:
Value: 9
Script: 12facdbb0eb291427b4b9a4745b2553c5e659dc2
--- Transaction e9e68fb36ddb0fb40f6dd7f24f2a867f33eb692c435765398257f8cc8e46cd55:
Input 0:
TXID:
Out: -1
Signature:
PubKey: 64353138386533393361346434363432306636316136333861636634386463656562343236643430
Output 0:
Value: 10
Script: 85d3eb79bdacda199724477c03807f64de9db9ce
$ ./blockchain_go getbalance -address 12jMcbWjGr9nPKj4QvKGyjgDyLeBqwLjeG
Balance of '12jMcbWjGr9nPKj4QvKGyjgDyLeBqwLjeG': 17
As you can see, transaction input (598b4e12b0bd16e87f7cdd108a4361c27c147e943fe7742a807dd3d8d0a7f2db) was used 2 times.
Assume I have 3 wallets: A(10 coins), B(0 coins), C(0 coins). then i'm trying to send from A -> B(1 coins) and A -> C(2 coins).
first transaction: A -> B (1 coins) and A -> A (9 coins)
second transaction: A -> C (2 coins) and A -> A (8 coins)
that will result A will have 17 coins instead of having only 7 coins left.
A(17 coins), B(1 coin), C(2 coins) ??
P.S. both transactions happened in NODE_ID=3001
P.S.2 NODE_ID=3002 was miner node.
Tks for u good job.
I find some problem in branch part5
file: base58.go
function Base58Encode:
//for b := range input {
for _, b := range input {
if b == 0x00 {
result = append([]byte{b58Alphabet[0]}, result...)
} else {
break
}
}
function Base58Encode:
//for b := range input {
for _,b := range input {
//if b == 0x00 {
if b == b58Alphabet[0] {
zeroBytes++
}
}
When I run the main in command line , an error tell me should set an env.var for NODE_ID
add miner(3002), pow:false?
============ Block 0000b3c686fec2b383f93118321671b53ad76eb3fe8ad935d4965d541f7fed8b ============
Height: 5
Prev. block: 00006162367236ae9b09bde586730b0de745e75cb1e2ef249b66b79e2d55d2bf
PoW: false
--- Transaction 1e238f0e1fc8c9d3f23ce0c50556eb5bd9c3ca6e6db147c1b5c43a98c7df3ff6:
Input 0:
TXID: 38e6896f2d3d10540d55be933dcaef97c6c0ca19f3bb3e5613fac7444a2c120d
Out: 1
Signature: da01b8af0b5b193aeeb85636e53984633f4b1f237ce82dbc878d04d3d6a6fb9ddc3c59ce13a4730cc8a34b13309fc4f8d8a5b92c71bcb63b8040a27226e276a5
PubKey: cd80976c2294f2489ad86b39b632a306aa9c66ecc4997d53be52a1a394dcccd313b5843acb081a3a9f952ad26595ce08848f64570f2334331a475e776efe1078
Output 0:
Value: 5
Script: b25d73a6ddfce73f5aca795bbad852c147c77d0c
Output 1:
Value: 3
Script: 5384ee841de66042f7c5fd31d59524039d109465
--- Transaction ee042fb8f7b65f65e472088b3844e8ea066f67ce4c088ba3685ad1cb73b45c67:
Input 0:
TXID: 559bd9c5eca48065e823b79001bac17b57e09fb09db094340329c251d3bd84a5
Out: 1
Signature: f751752dd965802beea641e2fc090404e3539117a9fbe82cbba8c1223673994870f3ae778c0dcc9301ab3bcf59b6fc4b1e00a8f56adbbb01629590e391573293
PubKey: f0c84bd964299b0967858861ff4f417d50ceb7b0ec8092b66081d5da7f07242f489f7a7e1d4d21d0e3c85b2a6d8ef1b2cb97a06e91343e55ea779f275526b36a
Output 0:
Value: 1
Script: b25d73a6ddfce73f5aca795bbad852c147c77d0c
Output 1:
Value: 7
Script: 42ded8275a628aefcedf5a8b5f97a4e20fb5d2ba
--- Transaction 7721a40249f0acf9c9174812bb6000769c237d027bb746f44e1900f33b3894c2:
Input 0:
TXID:
Out: -1
Signature:
PubKey: 38333638383464313961346437613733306533666231626435663737663639306635383138646563
Output 0:
Value: 10
Script: e74813eae1da851264c5c754da71bce354cd66d8
============ Block 00006162367236ae9b09bde586730b0de745e75cb1e2ef249b66b79e2d55d2bf ============
Height: 4
Prev. block: 00001458f1af04a3a0b03f4901bb4926887ad1d1f6518e2478635de3d1595a41
PoW: false
Can I translate these series articles to korean?
Non-issue, was confused of the order it was printing out.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.