16 emails to Mike Hearn, from his first questions to "I've moved on to other things. It's in good hands with Gavin and everyone." Satoshi's messages only; Hearn's left out
Document text
Research, not advice. Part of the Bitcoin research archive (October 2026). Claims labelled unverified, contested or fringe are reported, not endorsed; statuses of bills and rules are as of the date checked. Government, court and patent records are public domain; the research notes are CC BY 4.0.
Satoshi Nakamoto — emails to Mike Hearn, 2009–2011 (Satoshi's messages only) Satoshi Nakamoto — emails to Mike Hearn, 2009–2011 (Satoshi's messages only) Extracted 2026-10-09 for ~/Projects/bitcoin (research, not advice). Source: Gmail printouts of five threads published by Mike Hearn at https://plan99.net/~mike/satoshi-emails/ (thread1.html–thread5.html), retrieved 2026-10-09. Only Satoshi Nakamoto's own messages are kept (16 messages). Mike Hearn's messages in the same threads are left out because they are his writing; lines of Hearn's that Satoshi quoted inside his own replies are kept as part of Satoshi's message. Each kept message is the published HTML unchanged, except that one Gmail attachment icon is replaced by a text placeholder so this file loads nothing from the internet. Dates and times are as Gmail printed them for the account holder (Hearn), whose time zone the printout does not state. Contents #Date (as printed)ThreadSource 1Sun, Apr 12, 2009 at 10:44 PMQuestions about BitCointhread1.html 2Mon, Apr 13, 2009 at 11:00 PMQuestions about BitCointhread1.html 3Mon, Apr 13, 2009 at 11:11 PMQuestions about BitCointhread1.html 4Tue, Apr 14, 2009 at 7:41 PMQuestions about BitCointhread1.html 5Sat, Apr 18, 2009 at 6:16 PMQuestions about BitCointhread1.html 6Sat, Apr 18, 2009 at 10:52 PMQuestions about BitCointhread1.html 7Sun, Apr 19, 2009 at 2:14 AMQuestions about BitCointhread1.html 8Mon, Apr 27, 2009 at 12:11 AMLack of chargeback supportthread2.html 9Wed, Dec 29, 2010 at 10:42 PMMore BitCoin questionsthread3.html 10Fri, Jan 7, 2011 at 1:00 PMMore BitCoin questionsthread3.html 11Mon, Jan 10, 2011 at 4:34 PMMore BitCoin questionsthread3.html 12Mon, Jan 10, 2011 at 8:47 PMMore BitCoin questionsthread3.html 13Wed, Mar 9, 2011 at 5:15 PMOpen sourced my Java SPV implthread4.html 14Wed, Mar 9, 2011 at 7:39 PMOpen sourced my Java SPV implthread4.html 15Wed, Apr 20, 2011 at 11:39 AMHolding coins in an unspendable state for a rolling time windowthread5.html 16Sat, Apr 23, 2011 at 3:40 PMHolding coins in an unspendable state for a rolling time windowthread5.html 1. Questions about BitCoin — Sun, Apr 12, 2009 at 10:44 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Sun, Apr 12, 2009 at 10:44 PM To: Mike Hearn <[email protected]> Hi Mike, I'm glad to answer any questions you have. If I get time, I ought to write a FAQ to supplement the paper. There is only one global chain. The existing Visa credit card network processes about 15 million Internet purchases per day worldwide. Bitcoin can already scale much larger than that with existing hardware for a fraction of the cost. It never really hits a scale ceiling. If you're interested, I can go over the ways it would cope with extreme size. By Moore's Law, we can expect hardware speed to be 10 times faster in 5 years and 100 times faster in 10. Even if Bitcoin grows at crazy adoption rates, I think computer speeds will stay ahead of the number of transactions. I don't anticipate that fees will be needed anytime soon, but if it becomes too burdensome to run a node, it is possible to run a node that only processes transactions that include a transaction fee. The owner of the node would decide the minimum fee they'll accept. Right now, such a node would get nothing, because nobody includes a fee, but if enough nodes did that, then users would get faster acceptance if they include a fee, or slower if they don't. The fee the market would settle on should be minimal. If a node requires a higher fee, that node would be passing up all transactions with lower fees. It could do more volume and probably make more money by processing as many paying transactions as it can. The transition is not controlled by some human in charge of the system though, just individuals reacting on their own to market forces. Eventually, most nodes may be run by specialists with multiple GPU cards. For now, it's nice that anyone with a PC can play without worrying about what video card they have, and hopefully it'll stay that way for a while. More computers are shipping with fairly decent GPUs these days, so maybe later we'll transition to that. A key aspect of Bitcoin is that the security of the network grows as the size of the network and the amount of value that needs to be protected grows. The down side is that it's vulnerable at the beginning when it's small, although the value that could be stolen should always be smaller than the amount of effort required to steal it. If someone has other motives to prove a point, they'll just be proving a point I already concede. My choice for the number of coins and distribution schedule was an educated guess. It was a difficult choice, because once the network is going it's locked in and we're stuck with it. I wanted to pick something that would make prices similar to existing currencies, but without knowing the future, that's very hard. I ended up picking something in the middle. If Bitcoin remains a small niche, it'll be worth less per unit than existing currencies. If you imagine it being used for some fraction of world commerce, then there's only going to be 21 million coins for the whole world, so it would be worth much more per unit. Values are 64-bit integers with 8 decimal places, so 1 coin is represented internally as 100000000. There's plenty of granularity if typical prices become small. For example, if 0.001 is worth 1 Euro, then it might be easier to change where the decimal point is displayed, so if you had 1 Bitcoin it's now displayed as 1000, and 0.001 is displayed as 1. Ripple is interesting in that it's the only other system that does something with trust besides concentrate it into a central server. Satoshi [Quoted text hidden] 2. Questions about BitCoin — Mon, Apr 13, 2009 at 11:00 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Mon, Apr 13, 2009 at 11:00 PM To: Mike Hearn <[email protected]> Mike Hearn wrote: My best guess - it is the length of the global chain, and the rapid advance at the start is as the software downloads and verifies the preceding blocks in the chain as being valid. Right. I'm trying to think of more clear wording for that, maybe "%d network blocks" or "%d block chain". If we assume that 0.1% is a good risk rate, then z=5 thus any transaction must wait a bit less than an hour before being solidified in the chain. As micropayments for things like web content or virtual goods are by definition something that requires low overhead, waiting an hour seems like quite a significant hurdle. For the actual risk, multiply the 0.1% by the probability that the buyer is an attacker with a huge network of computers. For micropayments, you can safely accept the payment immediately. The size of the payment is too small for the effort to steal it. Micropayments are almost always for intellectual property, where there's no physical loss to the merchant. Anyone trying to steal a micropayment would probably not be a paying customer anyway, and if they want to steal intellectual property they can use the file sharing networks. Currently, businesses accept a certain chargeoff rate. I believe the risk with 1 or even 0 confirming blocks will be much less than the rate of chargebacks on verified credit card transactions. The usual scam against a merchant that doesn't wait for confirming blocks would be to send a payment to a merchant, then quickly try to propagate a double-spend to the network before the merchant's copy. What the merchant can do is broadcast his transaction and then monitor the network for any double-spend copies. The thief would not be able to broadcast during the monitoring period or else the merchant's node would receive a copy. The merchant would only have to monitor for a minute or two until most of the network nodes have his version and it's too late for the thief's version to catch up and reach many nodes. With just a minute or two delay, the chance of getting away without paying could be made much too low to scam. A thief usually needs a high probability of getting an item for free to make it worthwhile. Using a lot of CPU power to do the brute force attack discussed in the paper in addition to the above scam would not increase the thief's chances very much. Anything that grants access to something, like something that takes a while to download, access to a website, web hosting, a subscription or service, can be cancelled a few minutes later if the transaction is rejected. is confusing for me, because it appears the only way the honest chain can grow faster than a chain worked on by 1 attacking cpu is if the keyspace to scan looking for a partial collision is sharded evenly amongst the participating honest nodes. That way the speed at which collisions are found would be proportional to the number of nodes. Yet I don't see any discussion of such work sharding, which obviously adds complexity. The keyspace is huge, 2^256. The thing being hashed includes the node's public key and a random nonce, so the chance of any two nodes duplicating work on the same space is negligible. How is the required difficulty of each block communicated through the network and agreed upon? It's not communicated. The formula is hardcoded in the program and every node does the same calculation to know what difficulty is required for the next block. If someone diverged from the formula, their block would not be accepted by the majority. Thanks once again. I have yet more questions but this is enough for one email :) I will be happy to summarize these discussions into an FAQ-like document at some point. Apologies if the questions seem trivial. No problem, thanks for testing it on Mac Wine. Satoshi [Quoted text hidden] 3. Questions about BitCoin — Mon, Apr 13, 2009 at 11:11 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Mon, Apr 13, 2009 at 11:11 PM To: Mike Hearn <[email protected]> It keeps getting extended all the time. If it stopped, an attacker would have time to catch up. Don't worry, empty blocks aren't very big. As you say, it's the order of events that matters. [Quoted text hidden] 4. Questions about BitCoin — Tue, Apr 14, 2009 at 7:41 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Tue, Apr 14, 2009 at 7:41 PM To: Mike Hearn <[email protected]> I started implementing a marketplace feature earlier that facilitates offering things for sale and taking orders, it's only half done though. A bit like e-bay but without auctions, just "buy now". Among other things, it would make it easy for anyone to offer currency exchange. If you send to 1PhUXucRd8FzQved2KGK3g1eKfTHPGjgFu and e-mail me your bitcoin address, or IP if you can accept incoming connections, I'll send back the same amount +50. [Quoted text hidden] 5. Questions about BitCoin — Sat, Apr 18, 2009 at 6:16 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Sat, Apr 18, 2009 at 6:16 PM To: Mike Hearn <[email protected]> I sent back 32.51 and 50.00. I badly wanted to find some way to include a comment with indirect transfers, but there just wasn't a way to do it. Bitcoin uses EC-DSA, which was essential for making the block chain compact enough to be practical with today's technology because its signatures are an order of magnitude smaller than RSA. But EC-DSA can't encrypt messages like RSA, it can only be used to verify signatures. [Quoted text hidden] 6. Questions about BitCoin — Sat, Apr 18, 2009 at 10:52 PM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Sat, Apr 18, 2009 at 10:52 PM To: Mike Hearn <[email protected]> Got the 50. Transactions sent to a bitcoin address will always say "from: unknown". The transaction only tells who it's to. Sending by bitcoin address has a number of problems, but it's so nice having the fallback option to be able to send to anyone whether they're online or not. There are a number of ideas to try to improve things later. For now, if things work out like the real world where the vast majority of transactions are with merchants, they'll pretty much always make sure to set up to receive by IP. The P2P file sharing networks seem fairly successful at getting a large percentage of their users to set up their firewalls to forward a port. The "Generated (not accepted)" normally happens if two nodes find a block at close to the same time, one of them will not be accepted. It's normal and unavoidable. I plan in v0.1.6 to hide those, since they're just confusing and annoying and there's no reason for users to have to see them. While the network is still small like it is now, if you can't receive incoming connections you're at more of a disadvantage because you can't receive block announcements as directly. [Quoted text hidden] 7. Questions about BitCoin — Sun, Apr 19, 2009 at 2:14 AM Source page: https://plan99.net/~mike/satoshi-emails/thread1.html Satoshi Nakamoto <[email protected]>Sun, Apr 19, 2009 at 2:14 AM To: Mike Hearn <[email protected]> The list is: [email protected] Subscribe/unsubscribe page: http://lists.sourceforge.net/mailman/listinfo/bitcoin-list Archives: http://sourceforge.net/mailarchive/forum.php?forum_name=bitcoin-list I'll always announce new versions there. Automatic update, or at least notification of new versions, is definitely on the list. There could potentially be necessary changes in the future where nobody will want to talk to you until you upgrade, and there needs to be code in the older version to convey that to the user. This is all the harder in the context of not trusting anyone. Your approach to micropayments sounds right. At first, it might be a good idea to default to asking permission until the user gets comfortable and is ready to set it to automatic. The end goal though should get to something like you describe, where it's similar to using your cell phone without really having to think about the per minute charges. I looked at Google protocol buffers when they were released last year, but I had already written everything by then. What I did was something similar to Boost Serialisation. For this application, where I was parsing messages from strangers who might have extreme incentive to hack the protocol, it was necessary to make it as basic as possible so I could crawl over every line of code to convince myself it was airtight. It became clear that any unnecessary degrees of freedom in the binary format multiplied the potential angles of attack. You guys are so right though to standardize across the company on protocol buffers. I think you've got the optimal solution in the general case. 8. Lack of chargeback support — Mon, Apr 27, 2009 at 12:11 AM Source page: https://plan99.net/~mike/satoshi-emails/thread2.html Satoshi Nakamoto <[email protected]>Mon, Apr 27, 2009 at 12:11 AM To: Mike Hearn <[email protected]> I am not a lawyer and I can't possibly answer that. I suppose if the law applies to a bank or financial institution or other intermediary, then it would not apply since there is no bank involved, only two parties trading directly with each other, as they would in person with cash or barter with physical commodities. Bitcoin is fundamentally designed to be able to do non-reversible transactions, and there certainly are applications that need that. If someone wants the possibility of chargeback, they can use an escrow transaction, which isn't implemented yet but will be one of the next things. For instance, a transaction can be written to designate a third party to decide whether it is returned if the payer does not release it, with auto-release after a number of days. I'll implement a more basic form of escrow first, but the network infrastructure includes a predicate language that can express any number of options. 9. More BitCoin questions — Wed, Dec 29, 2010 at 10:42 PM Source page: https://plan99.net/~mike/satoshi-emails/thread3.html Satoshi Nakamoto <[email protected]>Wed, Dec 29, 2010 at 10:42 PM To: Mike Hearn <[email protected]> I have been working on a Java implementation of the simplified payment verification, with an eye to building a client that runs on Android phones. So I've been thinking a lot about storage requirements and the scalability of BitCoin, which led to some questions that the paper did not answer (maybe there could be a new version of the paper at some point, as I think aspects of it are now out of date). The simplified payment verification in the paper imagined you would receive transactions directly, as with sending to IP address which nobody uses, or a node would index all transactions by public key and you could download them like downloading mail from a mail server. Instead, I think client-only nodes should receive full blocks so they can scan them for their own transactions. They don't need to store them or index them. For the initial download, they only need to download headers, since there couldn't be any payments before the first time the program was run (a header download command was added in 0.3.18). From then on, they download full blocks (but only store the headers). Code for client-only mode is mostly implemented. There's a feature branch on github with it, also I'm attaching the patch to this message. Here's some more about it: "Here's my client-mode implementation so far. Client-only mode only records block headers and doesn't use the tx index. It can't generate, but it can still send and receive transactions. It's not fully finished for use by end-users, but it doesn't matter because it's a complete no-op if fClient is not enabled. At this point it's mainly documentation showing the cut-lines for client-only re-implementers. With fClient=true, I've only tested the header-only initial download. A little background. CBlockIndex contains all the information of the block header, so to operate with headers only, I just maintain the CBlockIndex structure as usual. The nFile/nBlockPos are null, since the full block is not recorded on disk. The code to gracefully switch between client-mode on/off without deleting blk*.dat in between is not implemented yet. It would mostly be a matter of having non-client LoadBlockIndex ignore block index entries with null block pos. That would make it re-download those as full blocks. Switching back to client-mode is no problem, it doesn't mind if the full blocks are there. If the initial block download becomes too long, we'll want client mode as an option so new users can get running quickly. With graceful switch-off of client mode, they can later turn off client mode and have it download the full blocks if they want to start generating. They should rather just use a getwork miner to join a pool instead. Client-only re-implementations would not need to implement EvalScript at all, or at most just implement the five ops used by the standard transaction templates." Specifically, BitCoin has a variety of magic numbers and neither the code nor the paper explain where they came from. For example, the fact that inflation ceases when 21 million coins have been issued. This number must have been arrived at somehow, but I can't see how. Educated guess, and the maths work out to round numbers. I wanted something that would be not too low if it was very popular and not too high if it wasn't. Another is the 10 minute block target. I understand this was chosen to allow transactions to propagate through the network. However existing large P2P networks like BGP can propagate new data worldwide in <1 minute. If propagation is 1 minute, then 10 minutes was a good guess. Then nodes are only losing 10% of their work (1 minute/10 minutes). If the CPU time wasted by latency was a more significant share, there may be weaknesses I haven't thought of. An attacker would not be affected by latency, since he's chaining his own blocks, so he would have an advantage. The chain would temporarily fork more often due to latency. The final number I'm interested in is the 500kb limit on block sizes. According to Wikipedia, Visa alone processed 62 billion transactions in 2009. Dividing through we get an average of 2000 transactions per second, so peak rate is probably around double that at 4000 transactions/sec. With a ten minute block target, at peak a block might need to contain 2.4 million transactions, which just won't fit into 500kb. Is this 500kb a temporary limitation that will be slowly removed over time from the official client or something more fundamental? A higher limit can be phased in once we have actual use closer to the limit and make sure it's working OK. Eventually when we have client-only implementations, the block chain size won't matter much. Until then, while all users still have to download the entire block chain to start, it's nice if we can keep it down to a reasonable size. With very high transaction volume, network nodes would consolidate and there would be more pooled mining and GPU farms, and users would run client-only. With dev work on optimising and parallelising, it can keep scaling up. Whatever the current capacity of the software is, it automatically grows at the rate of Moore's Law, about 60% per year. diff -u old\db.cpp new\db.cpp --- old\db.cpp Sat Dec 18 18:35:59 2010 +++ new\db.cpp Sun Dec 19 20:53:59 2010 @@ -464,29 +464,32 @@ ReadBestInvalidWork(bnBestInvalidWork); // Verify blocks in the best chain - CBlockIndex* pindexFork = NULL; - for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) + if (!fClient) { - if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks")) - break; - CBlock block; - if (!block.ReadFromDisk(pindex)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); - if (!block.CheckBlock()) + CBlockIndex* pindexFork = NULL; + for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { - printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); - pindexFork = pindex->pprev; + if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks")) + break; + CBlock block; + if (!block.ReadFromDisk(pindex)) + return error("LoadBlockIndex() : block.ReadFromDisk failed"); + if (!block.CheckBlock()) + { + printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + pindexFork = pindex->pprev; + } + } + if (pindexFork) + { + // Reorg back to the fork + printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); + CBlock block; + if (!block.ReadFromDisk(pindexFork)) + return error("LoadBlockIndex() : block.ReadFromDisk failed"); + CTxDB txdb; + block.SetBestChain(txdb, pindexFork); } - } - if (pindexFork) - { - // Reorg back to the fork - printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); - CBlock block; - if (!block.ReadFromDisk(pindexFork)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); - CTxDB txdb; - block.SetBestChain(txdb, pindexFork); } return true; diff -u old\main.cpp new\main.cpp --- old\main.cpp Sat Dec 18 18:35:59 2010 +++ new\main.cpp Sun Dec 19 20:53:59 2010 @@ -637,6 +637,9 @@ if (!IsStandard()) return error("AcceptToMemoryPool() : nonstandard transaction type"); + if (fClient) + return true; + // Do we already have it? uint256 hash = GetHash(); CRITICAL_BLOCK(cs_mapTransactions) @@ -1308,23 +1311,26 @@ if (!CheckBlock()) return false; - //// issue here: it doesn't know the version - unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); - - map<uint256, CTxIndex> mapUnused; - int64 nFees = 0; - foreach(CTransaction& tx, vtx) + if (!fClient) { - CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); - nTxPos += ::GetSerializeSize(tx, SER_DISK); + //// issue here: it doesn't know the version + unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); + + map<uint256, CTxIndex> mapUnused; + int64 nFees = 0; + foreach(CTransaction& tx, vtx) + { + CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); + nTxPos += ::GetSerializeSize(tx, SER_DISK); - if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex, nFees, true, false)) + if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex, nFees, true, false)) + return false; + } + + if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) return false; } - if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) - return false; - // Update block index on disk without changing it in memory. // The memory index structure will be changed after the db commits. if (pindex->pprev) @@ -1378,7 +1384,7 @@ foreach(CBlockIndex* pindex, vDisconnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!block.ReadFromDisk(pindex, !fClient)) return error("Reorganize() : ReadFromDisk for disconnect failed"); if (!block.DisconnectBlock(txdb, pindex)) return error("Reorganize() : DisconnectBlock failed"); @@ -1395,7 +1401,7 @@ { CBlockIndex* pindex = vConnect[i]; CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!block.ReadFromDisk(pindex, !fClient)) return error("Reorganize() : ReadFromDisk for connect failed"); if (!block.ConnectBlock(txdb, pindex)) { @@ -1526,7 +1532,7 @@ txdb.Close(); - if (pindexNew == pindexBest) + if (!fClient && pindexNew == pindexBest) { // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; @@ -1547,10 +1553,6 @@ // These are checks that are independent of context // that can be verified before saving an orphan block. - // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) - return error("CheckBlock() : size limits failed"); - // Check proof of work matches claimed amount if (!CheckProofOfWork(GetHash(), nBits)) return error("CheckBlock() : proof of work failed"); @@ -1559,6 +1561,13 @@ if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return error("CheckBlock() : block timestamp too far in the future"); + if (fClient && vtx.empty()) + return true; + + // Size limits + if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) + return error("CheckBlock() : size limits failed"); + // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) return error("CheckBlock() : first tx is not coinbase"); @@ -1623,13 +1632,14 @@ return error("AcceptBlock() : out of disk space"); unsigned int nFile = -1; unsigned int nBlockPos = 0; - if (!WriteToDisk(nFile, nBlockPos)) - return error("AcceptBlock() : WriteToDisk failed"); + if (!fClient) + if (!WriteToDisk(nFile, nBlockPos)) + return error("AcceptBlock() : WriteToDisk failed"); if (!AddToBlockIndex(nFile, nBlockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); // Relay inventory, but don't relay old inventory during initial block download - if (hashBestChain == hash) + if (!fClient && hashBestChain == hash) CRITICAL_BLOCK(cs_vNodes) foreach(CNode* pnode, vNodes) if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 55000)) @@ -2405,6 +2415,8 @@ { if (fShutdown) return true; + if (fClient && inv.type == MSG_TX) + continue; pfrom->AddInventoryKnown(inv); bool fAlreadyHave = AlreadyHave(txdb, inv); @@ -2441,6 +2453,9 @@ if (inv.type == MSG_BLOCK) { + if (fClient) + return true; + // Send block from disk map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash); if (mi != mapBlockIndex.end()) @@ -2486,6 +2501,8 @@ else if (strCommand == "getblocks") { + if (fClient) + return true; CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; @@ -2556,6 +2573,8 @@ else if (strCommand == "tx") { + if (fClient) + return true; vector<uint256> vWorkQueue; CDataStream vMsg(vRecv); CTransaction tx; @@ -2620,6 +2639,33 @@ if (ProcessBlock(pfrom, &block)) mapAlreadyAskedFor.erase(inv); + } + + + else if (strCommand == "headers") + { + if (!fClient) + return true; + vector<CBlock> vHeaders; + vRecv >> vHeaders; + + uint256 hashBestBefore = hashBestChain; + foreach(CBlock& block, vHeaders) + { + block.vtx.clear(); + + printf("received header %s\n", block.GetHash().ToString().substr(0,20).c_str()); + + CInv inv(MSG_BLOCK, block.GetHash()); + pfrom->AddInventoryKnown(inv); + + if (ProcessBlock(pfrom, &block)) + mapAlreadyAskedFor.erase(inv); + } + + // Request next batch + if (hashBestChain != hashBestBefore) + pfrom->PushGetBlocks(pindexBest, uint256(0)); } diff -u old\main.h new\main.h --- old\main.h Sat Dec 18 18:35:59 2010 +++ new\main.h Sun Dec 19 20:53:59 2010 @@ -619,6 +619,8 @@ bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) { + assert(!fClient); + CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"); if (!filein) return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); @@ -1174,6 +1176,7 @@ bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true) { + assert(!fClient); SetNull(); // Open history file to read @@ -1231,7 +1234,7 @@ // -// The block chain is a tree shaped structure starting with the +// The block index is a tree shaped structure starting with the // genesis block at the root, with each block potentially having multiple // candidates to be the next block. pprev and pnext link a path through the // main/longest chain. A blockindex may have multiple pprev pointing back diff -u old\net.cpp new\net.cpp --- old\net.cpp Wed Dec 15 22:33:09 2010 +++ new\net.cpp Sun Dec 19 21:51:27 2010 @@ -51,7 +51,15 @@ pindexLastGetBlocksBegin = pindexBegin; hashLastGetBlocksEnd = hashEnd; - PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); + /// Client todo: After the initial block header download, start using getblocks + /// here instead of getheaders. For blocks generated after the first time the + /// program was run, we need to download full blocks to watch for received + /// transactions in them. We're able to download headers only for blocks + /// generated before we ever ran because they can't contain txes for us. + if (::fClient) + PushMessage("getheaders", CBlockLocator(pindexBegin), hashEnd); + else + PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); } [attachment icon; source: https://ssl.gstatic.com/ui/v1/icons/mail/images/txt.gif]client-mode.patch 11K 10. More BitCoin questions — Fri, Jan 7, 2011 at 1:00 PM Source page: https://plan99.net/~mike/satoshi-emails/thread3.html Satoshi Nakamoto <[email protected]>Fri, Jan 7, 2011 at 1:00 PM To: Mike Hearn <[email protected]> I reached the same conclusions about client only nodes and this is what I've been implementing. I'm nearly there ..... I have block chain download, parsing and verification of the blocks/transactions done, with creation of spend transactions almost done. That's great! The first client-only implementation will really start to move things to the next step. Is it going to be open source, or Google proprietary? 11. More BitCoin questions — Mon, Jan 10, 2011 at 4:34 PM Source page: https://plan99.net/~mike/satoshi-emails/thread3.html Satoshi Nakamoto <[email protected]>Mon, Jan 10, 2011 at 4:34 PM To: Mike Hearn <[email protected]> Open source. Perfect. Once your code shows how to simplify it down, other authors can follow your lead. Client is a less daunting challenge than full implementation. If it's within reach of more developers, they'll come up with more polished UI and other things I didn't think of. I expect the original software will become the industrial old thing used by GPU farms and pool servers. BTW, later a good feature for a client version is to keep your private keys encrypted and you give your password each time you send. I managed to spend my first coins on the testnet with my app a few days ago, hopefully will get another chance to make progress this weekend. Probably will have something to show publically sometime in Feb, touch wood. Great, keep me updated. I wanted something that would be not too low if it was very popular and not too high if it wasn't. It'd be interesting to see the working for this. In some sense the number of coins is arbitrary as the nanocoin representation means the issuance is so huge it's practically infinite. It works out to an even 10 minutes per block: 21000000 / (50 BTC * 24hrs * 365days * 4years * 2) = 5.99 blocks/hour I fudged it to 364.58333 days/year. The halving of 50 BTC to 25 BTC is after 210000 blocks or around 3.9954 years, which is approximate anyway based on the retargeting mechanism's best effort. I thought about 100 BTC and 42 million, but 42 million seemed high. I wanted typical amounts to be in a familiar range. If you're tossing around 100000 units, it doesn't feel scarce. The brain is better able to work with numbers from 0.01 to 1000. If it gets really big, the decimal can move two places and cents become the new coins. 12. More BitCoin questions — Mon, Jan 10, 2011 at 8:47 PM Source page: https://plan99.net/~mike/satoshi-emails/thread3.html Satoshi Nakamoto <[email protected]>Mon, Jan 10, 2011 at 8:47 PM To: Mike Hearn <[email protected]> By the way, if you didn't see it already, there's a discussion on the security of secp256k1 on the forum: http://www.bitcoin.org/smf/index.php?topic=2699.0 Hal (i presume this is Hal Finney) Yes, it's him. He was supportive on the Cryptography list and ran one of the first nodes. seems to think the curve is at higher risk of attack than random curves. I guess you chose secp256k1 for the mentioned performance improvement? I must admit, this project was 2 years of development before release, and I could only spend so much time on each of the many issues. I found guidance on the recommended size for SHA and RSA, but nothing on ECDSA which was relatively new. I took the recommended key size for RSA and converted to equivalent key size for ECDSA, but then increased it so the whole app could be said to be 256-bit security. I didn't find anything to recommend a curve type so I just... picked one. Hopefully there is enough key size to make up for any deficiency. At the time, I was concerned whether the bandwidth and storage sizes would be practical even with ECDSA. RSA's huge keys were out of the question. Storage and bandwidth seemed tighter back then. I felt the size was either only just becoming practical, or would be soon. When I presented it, I was surprised nobody else was concerned about size, though I was also surprised how many issues they argued, and more surprised that every single one was something I had thought of and solved. As it turns out, ECDSA verification time may be the greater bottleneck. (In my tests, OpenSSL was taking 3.5ms per ECDSA verify, or about 285 verifies per second) Client versions bypass the problem. As things have evolved, the number of people who need to run full nodes is less than I originally imagined. The network would be fine with a small number of nodes if processing load becomes heavy. 13. Open sourced my Java SPV impl — Wed, Mar 9, 2011 at 5:15 PM Source page: https://plan99.net/~mike/satoshi-emails/thread4.html Satoshi Nakamoto <[email protected]>Wed, Mar 9, 2011 at 5:15 PM To: Mike Hearn <[email protected]> I hope you are doing well. I finally got all the lawyers happy enough to release BitCoinJ under the Google name using the Apache 2 license: It's incomplete - notably it doesn't properly handle block chain splits yet - but the rest is coming. I put a lot of work into documentation and comments so hopefully it'll open up BitCoin to a new audience who weren't able to understand/build the current code. Over the next month or two I'll be finishing off some of the bigger missing pieces for a full client-mode implementation. That's great news! Much complexity can be left behind in a clean rewrite with only client requirements, and it opens it to Java developers too. I know you are busy right now but I'm hoping you can find time to answer a few questions I had. I'm happy to answer any questions. As part of doing full SPV I'm thinking of adding a getmerklebranch message to the protocol. This would return a set of {blockhash, branch} pairs That's a CMerkleTx given tx hashes, so allowing verification of a broadcast transaction before it was incorporated into a block without storing the full chain. Does that approach sound good to you? I don't understand. A merkle branch links a tx back to a block, which only has significance if the block exhibits proof-of-work. Linking back to an as-yet unsolved block proves nothing. Network nodes are able to verify 0-conf txes because they have the complete tx index, so they can: 1) verify signatures against dependencies. 2) say that they haven't seen another spend yet, because they know about every tx in existence. Are you talking about CMerkleTxes for the tx's dependencies? That would get part 1), but not part 2). If you don't know about all txes in existence, I don't know how to do 2). You could only rely on trusting other nodes for that. That trust can be distributed over multiple nodes. Nodes only relay transactions they accept as valid. If you receive inv messages for a tx from all the nodes you're connected to, they're attesting that it's valid and the first spend they saw. Also, I've been thinking of exploring different transaction types lately, eg by removing the IsStandard() checks for the testnet. Very good idea. That should definitely be allowed on -testnet. It's clear you put a lot of thought into transactions beyond simply moving coins around up front, but unfortunately none of it was in the paper or documented in the code. Escrow, multi-pay and so on are all interesting but I was wondering if you could compile a list of ideas for things we can do with the scripting language at some point. Finally, the code that allows for transaction replacement has been disabled but the comment doesn't say why. Is this just to reduce the attack surface/complexity or is there a deeper reason? Just to reduce surface area. It wouldn't help with increasing tx fee. A tx starts being valid at nLockTime. It wouldn't work to have a tx that stops being valid at a certain time; once a tx ever becomes valid, it must stay valid permanently. See these threads: http://www.bitcoin.org/smf/index.php?topic=1786.msg22119#msg22119 http://www.bitcoin.org/smf/index.php?topic=2181.msg28729#msg28729 I haven't fully understood why sequence numbers are a property of the tx inputs rather than the tx itself. It's for contracts. An unrecorded open transaction can keep being replaced until nLockTime. It may contain payments by multiple parties. Each input owner signs their input. For a new version to be written, each must sign a higher sequence number (see IsNewerThan). By signing, an input owner says "I agree to put my money in, if everyone puts their money in and the outputs are this." There are other options in SignatureHash such as SIGHASH_SINGLE which means "I agree, as long as this one output (i.e. mine) is what I want, I don't care what you do with the other outputs.". If that's written with a high nSequenceNumber, the party can bow out of the negotiation except for that one stipulation, or sign SIGHASH_NONE and bow out completely. The parties could create a pre-agreed default option by creating a higher nSequenceNumber tx using OP_CHECKMULTISIG that requires a subset of parties to sign to complete the signature. The parties hold this tx in reserve and if need be, pass it around until it has enough signatures. One use of nLockTime is high frequency trades between a set of parties. They can keep updating a tx by unanimous agreement. The party giving money would be the first to sign the next version. If one party stops agreeing to changes, then the last state will be recorded at nLockTime. If desired, a default transaction can be prepared after each version so n-1 parties can push an unresponsive party out. Intermediate transactions do not need to be broadcast. Only the final outcome gets recorded by the network. Just before nLockTime, the parties and a few witness nodes broadcast the highest sequence tx they saw. 14. Open sourced my Java SPV impl — Wed, Mar 9, 2011 at 7:39 PM Source page: https://plan99.net/~mike/satoshi-emails/thread4.html Satoshi Nakamoto <[email protected]>Wed, Mar 9, 2011 at 7:39 PM To: Mike Hearn <[email protected]> See these threads: http://www.bitcoin.org/smf/index.php?topic=1786.msg22119#msg22119 http://www.bitcoin.org/smf/index.php?topic=2181.msg28729#msg28729 I see. So right now fees are tricky because you have to decide up front what the fee should be, and if you guess too low, there's no way to correct the transaction and though the network will eventually forget it, your wallet still records that you spent the coins. This has already started happening. The network won't forget, and the owner's client will keep rebroadcasting it. The overflow transaction was remembered by the network for several months even as the remaining 0.3.8 nodes diminished. Priority includes age, so as a transaction waits it ages and will eventually have enough priority. See one of the links above where I contemplate sending an honest double-spend to increase the fee. It's a lot of work but could be done. I don't think it's worth it right now. The current system, where nodes make sure to include enough fee for current conditions and the network makes sure all transactions get processed eventually, works well enough. Gavin is fixing the oversight where nodes didn't check the priority of their own transactions when writing them. Users still worried about processing speed uncertainty should think of it as encouragement to include a fee. There's an unfinished part of the protocol that deals with setting up publisher/subscriber channels for distributed routing via the network. What was the purpose of this? Was the idea to have a p2p market or did it have some kind of lower level function, like perhaps broadcasting expected tx fees? I was trying to implement an eBay style marketplace built in to the client. Publish/subscribe would be used for broadcasting product offers and ratings/reviews. Your reviews would be weighted by the blocks you've generated. I rightly abandoned it in favour of JSON-RPC, so other authors could implement it externally. The publish/subscribe "meet in the middle" mechanism was an interesting concept, but nothing remains that uses it. It was part of writing code to explore the most technically demanding use cases and make sure Bitcoin could support everything that might be needed in the future, given the locked-in nature of the rules once the block chain started. There was an interesting discussion of generalizing BitCoin some months ago, but we struggled to fully understand how you planned to achieve it. I think I understood the concept of placing another merkle tree on top of multiple separate chains: http://www.bitcoin.org/smf/index.php?topic=3414.msg48171#msg48171 But I didn't understand your comment about having 200 bytes for backwards compatibility. Also, I guess this is obvious, but to be super clear - in your idea the alternative chains would share exactly the same format and sets of verification rules as BitCoin (the same script language etc), so all miners can verify all blocks even if they are non-financial in nature? And then the point of having separate block chains is simply to manage storage costs and bandwidth for client-mode implementations? No, other chains do not follow Bitcoin's rules. They are completely independent chains. They share nothing except the miners. The other network's definition of proof-of-work is to make a solved (according to their own chain's difficulty) Bitcoin-format block that has a hash of their own block in it. They don't care if the Bitcoin block is valid or used by Bitcoin, but it allows miners to work both chains at once. Procedure to hash a BitDNS block: - hash the BitDNS block - construct a Bitcoin block - insert the BitDNS hash into the scriptSig of tx 0 in the Bitcoin block - hash the Bitcoin block The BitDNS block is valid if that hash is below BitDNS's target. The BitDNS block needs to have with it about 200 bytes of data needed to reconstruct the Bitcoin block used in the hash: - the Bitcoin block header - the merkle branch to tx 0 - tx 0 (btw, tx 0's prev hash is always 0 so leaving that out saves 32 bytes) Note that it doesn't matter if the fodder "Bitcoin block" was actually valid in the Bitcoin chain, though it could have been. To BitDNS, it's just a bunch of salt necessary to do its convoluted hash calculation. If a miner is only mining for BitDNS and doesn't care about Bitcoin, it would use a blank Bitcoin block of all zeroes (except the nonce). To further expand the idea for extensibility, consider instead of putting the BitDNS block hash in tx 0, you put the root of a merkle tree that includes BitDNS. This is the merkle tree that is conceptually at the top. 15. Holding coins in an unspendable state for a rolling time window — Wed, Apr 20, 2011 at 11:39 AM Source page: https://plan99.net/~mike/satoshi-emails/thread5.html Satoshi Nakamoto <[email protected]>Wed, Apr 20, 2011 at 11:39 AM To: Mike Hearn <[email protected]> If the script language is not stateless, if it has access to any outside information that changes or varies between nodes, attackers can use it to fork the chain. The only exception is if it is always false before a certain time and permanently true after, which is implemented with nLockTime. Since Google is trusted, couldn't users pay a token deposit to Google and Google pays them back when they close the account? To answer your question though, yes it can be done without using trust: Tx 1 from User pays to a script that requires the signature of both Google and User to spend. Tx 2 (the contract) spends Tx 1 and pays it to User. nLockTime is the time to release the money. Steps: 1) Google gives User a pubkey to use in creating Tx 1. 2) User privately creates Tx 1, does not broadcast it yet. 3) User gives the hash of Tx 1 to Google. 4) Google signs its part of Tx 2, with nLockTime set, and gives it to User. 5) User broadcasts Tx 1. 6) User signs his half of Tx 2 and broadcasts it. With these steps, the user already has Google's signed half of Tx 2 in hand before he broadcasts Tx 1, so he is assured of what bargain he is signing the money to. This is the general pattern for safely signing contracts. Tx 2 is prepared first so the parties know what they're paying into. Tx 1 is broadcast to lock up the money and assign it to Tx 2. In other words, all parties assign their money to a pool that is controlled by the unanimous agreement of the group, but first the group has already signed agreement for the default action to take with the money, or partially signed multiple available options that a party can complete by adding the last signature. By mutual agreement, the parties can always write another version of Tx 2 that releases the money immediately. [Quoted text hidden] 16. Holding coins in an unspendable state for a rolling time window — Sat, Apr 23, 2011 at 3:40 PM Source page: https://plan99.net/~mike/satoshi-emails/thread5.html Satoshi Nakamoto <[email protected]>Sat, Apr 23, 2011 at 3:40 PM To: Mike Hearn <[email protected]> I had a few other things on my mind (as always). One is, are you planning on rejoining the community at some point (eg for code reviews), or is your plan to permanently step back from the limelight? I've moved on to other things. It's in good hands with Gavin and everyone. I do hope your BitcoinJ continues to be developed into an alternative client. It gives Java devs something to work on, and it's easier with a simpler foundation that doesn't have to do everything. It'll get critical mass when impatient new users can get started using it while the other one is still downloading the block chain.