Bitcoin Forum
June 21, 2025, 01:28:35 AM *
News: Pizza day contest voting
 
   Home   Help Search Login Register More  
Pages: « 1 2 [3] 4 »  All
  Print  
Author Topic: "Proof of Work" - A game about the history of Bitcoin  (Read 834 times)
askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 20, 2025, 08:48:26 AM
Last edit: May 25, 2025, 07:57:44 AM by askii
Merited by stwenhao (1)
 #41

How to save a game, to load it later?
Reaching 3k blocks again, and waiting for 6 halvings, will take some time.
Dang, sorry, there's no way to save right now Cry

I honestly didn't expect anyone to leave it running or play for that long haha. I've just added a little "dev tool", if you go to the SATMiner console and enter:
Code:
pre_mine <N>
where N is the number of blocks, it will pre mine those number of those blocks (after you refresh the page) so you don't have to wait that long again. It's a bit janky in that you'll need to let the network difficulty calibrate for maybe a minute (the blocks are pre mined instantly, so they don't impact difficulty) but I think it should work fine other than that.

When I have some time I'll implement saving.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 20, 2025, 11:43:10 AM
Merited by askii (1)
 #42

Quote
I honestly didn't expect anyone to leave it running or play for that long haha.
Oh, there are many things to test, if you keep it running. For example: the original client halts the chain, if timestamps will overflow. But: if hashrate will keep growing, then uint256 values can overflow, which will also halt the chain. And there are other edge cases, for example to see, if satoshis are halved correctly (or if someone used some floating point values, and will suddenly introduce fractional satoshis; or if things are always rounded down).

Also I noticed, that $0.01 is probably not the smallest indivisible unit, because I saw $0.00 in one box, while seeing $0.01 in another, so I expect some floating point data types.

Another thing is that as long as the price is constantly going up in the long-term, the best strategy is to simply mine the first coins on CPUs, wait for the value of them to raise (because having negative balance in dollars have no consequences), and then trade the rest of the coins from the exchange, when they will mine everything, and happily sell all of that, without asking any questions. Also, when it comes to trading, it should probably allow putting some order into some kind of orderbook, instead of allowing only buying and selling things on-the-spot.

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 20, 2025, 01:56:55 PM
Merited by stwenhao (1)
 #43

Oh, there are many things to test, if you keep it running. For example: the original client halts the chain, if timestamps will overflow. But: if hashrate will keep growing, then uint256 values can overflow, which will also halt the chain. And there are other edge cases, for example to see, if satoshis are halved correctly (or if someone used some floating point values, and will suddenly introduce fractional satoshis; or if things are always rounded down).
Amounts are stored internally as satoshis (integers) in the game, halving follows the same logic as the core client, and you're not allowed to send fractional satoshis, so fractional satoshis are impossible, or should be at least. And unless you leave the game running for the next hundred years, I don't think timestamps nor chainwork will overflow Cheesy

Also I noticed, that $0.01 is probably not the smallest indivisible unit, because I saw $0.00 in one box, while seeing $0.01 in another, so I expect some floating point data types.
This is less likely a floating point error and more likely a rounding error on my part, I must've made the mistake of rounding numbers inconsistently somewhere, I'll go have a look. But floating points are generally only used for fiat anyways, not chain logic (except calculating certain probabilities).

Another thing is that as long as the price is constantly going up in the long-term, the best strategy is to simply mine the first coins on CPUs, wait for the value of them to raise (because having negative balance in dollars have no consequences), and then trade the rest of the coins from the exchange, when they will mine everything, and happily sell all of that, without asking any questions.
Kind of like in real life! If only I could rewind time and get 50 BTC for nothing... But yes, going into debt will most likely have to be a lose condition to encourage the player to keep up. Things will become slightly more nuanced when I add mining pools and all the other features, I think there will be strategies that prove to be much better.

Also, when it comes to trading, it should probably allow putting some order into some kind of orderbook, instead of allowing only buying and selling things on-the-spot.
Good idea, I'll add this to my list. Maybe even derivatives, long/short trading.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 20, 2025, 03:25:55 PM
 #44

Quote
But yes, going into debt will most likely have to be a lose condition to encourage the player to keep up.
Maybe not a losing condition, but rather keeping the positive balance should be required to keep mining. Which means, that miners could simply stop, and you could be forced to pay for electricity, to mine new coins. Or: payment could be deducted upfront, and then miners will run for upfront agreed period of time. And also, selling old miners could be possible, to get more funds when needed.

Quote
Maybe even derivatives, long/short trading.
For the start, a simple thing like one more field will do. Instead of having an option to "sell 1 SAT here and now for $0.89", it should be possible to put an order, to "sell 1 SAT for at least $1.23, unless it will be filled or cancelled". If there are no other players, you can start from a single buy order, and a single sell order, and improve it later, when you will add more parties to the simulation.

By the way: initially I thought, that I can mine more blocks, but the counter seems to be stuck at 3066 total blocks for some reason. So, the status from the screen is not just a snapshot: the network cannot produce block number 3067 for some reason (maybe because of integer precision?).

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 20, 2025, 11:21:26 PM
Merited by stwenhao (1)
 #45

By the way: initially I thought, that I can mine more blocks, but the counter seems to be stuck at 3066 total blocks for some reason. So, the status from the screen is not just a snapshot: the network cannot produce block number 3067 for some reason (maybe because of integer precision?).
Yeah there was an integer precision bug before I added the pre mining. If you refresh the page it should be fixed, you can pre mine the same number of blocks or more to verify (or wait, but it's the same thing).

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 24, 2025, 08:28:05 AM
Merited by askii (1)
 #46

I think I hacked the exchange:
Code:
wallet_PK == network_params.exchange_cold_address
true
And then, I can just turn off my miners, and see, how the whole network will give me all coins.

By the way, I wonder, if you want to make it similar to Cookie Clicker, where the latest possible cookie maker is called "JavaScript console".

Quote
you can pre mine the same number of blocks or more to verify (or wait, but it's the same thing)
No, they are not the same. If you generate blocks from the command line, then the difficulty doesn't change. However, if you let the difficulty grow exponentially, then it can reach some limits, where producing next blocks is no longer possible.

Quote
And unless you leave the game running for the next hundred years, I don't think timestamps nor chainwork will overflow
Chainwork will overflow quite quickly, if it can grow exponentially. If you have 2^256 maximum chainwork, then if network hashrate will double only 256 times in a row, it will always overflow. And I guess, if you fixed it that way or another, then it will just shift the problem from block number 3067 to some bigger value, but I guess there is still some limit, and now I am trying to check it.

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 24, 2025, 09:52:41 AM
Merited by stwenhao (1)
 #47

I think I hacked the exchange:
Code:
wallet_PK == network_params.exchange_cold_address
true
And then, I can just turn off my miners, and see, how the whole network will give me all coins.
Yep, I suppose that's a natural console "exploit" as is tradition with all javascript games  Cheesy. I figured that since all the other network participants are "fake" I'd just have all coins not mined by the player sent to and kept in a single address, to be used for the exchange and other purposes down the line.

By the way, I wonder, if you want to make it similar to Cookie Clicker, where the latest possible cookie maker is called "JavaScript console".
It'd be funny, but I think it would break immersion a little  Grin

No, they are not the same. If you generate blocks from the command line, then the difficulty doesn't change. However, if you let the difficulty grow exponentially, then it can reach some limits, where producing next blocks is no longer possible.
Network hash rate (and thus difficulty) doesn't always grow exponentially - it's actually a function of the market price. So, the same way the maximum market price is definitively capped, it crashes, and doesn't grow forever, it's the same deal with NHR, unless I misunderstand what you mean. The difficulty is also adjusted by block time over the adjustment interval, same way as bitcoin, so it can never get "too hard" and make blocks impossible unless there is a gigantic hash rate drop, which should never happen.

Chainwork will overflow quite quickly, if it can grow exponentially. If you have 2^256 maximum chainwork, then if network hashrate will double only 256 times in a row, it will always overflow. And I guess, if you fixed it that way or another, then it will just shift the problem from block number 3067 to some bigger value, but I guess there is still some limit, and now I am trying to check it.
Theoretically yes, if it doubled 256 times, but as I addressed above, this will guaranteed never happen in the scope of the game because the hash rate simply cannot reach that high, not even close  Roll Eyes

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 25, 2025, 02:16:33 PM
Last edit: May 25, 2025, 04:23:31 PM by stwenhao
Merited by askii (3)
 #48

Now I can generate addresses, based on seeds. There are only 2^32 possible combinations, so now I know, how exchange addresses were generated:
Code:
+------------+------------------------------------+
| seed       | address                            |
+------------+------------------------------------+
| 0x22dd69be | 1teDcUjNzJdjiBesXDfsSUeeQUQYLQdQ5M |
| 0x1ee35ff3 | 1EYFqf3ot5nY1q7gfCEPP5pL3VEtBEN1wy |
+------------+------------------------------------+
I also reached vanity address generator. However, it requires real Proof of Work, so it takes some effort, to mine addresses with given prefixes:
Code:
+------------+------------------------------------+
| seed       | address                            |
+------------+------------------------------------+
| 0x1fca38ab | 1teDcqKiZHW13b8h2d4S7xtxV4jd6dAkNd |
| 0x2054e435 | 1teDcB8TQnFhT2vwPztSqS5DXrqH13DUc3 |
| 0x213a0431 | 1teDcHeuqHuJ3zeFGbhTuSA6fZgCzC3jfK |
| 0x2187e7e9 | 1teDc6bnAcnEbaxzWWv6yXdPcH1qHtUXvH |
| 0x22dd69be | 1teDcUjNzJdjiBesXDfsSUeeQUQYLQdQ5M | exchange address
| 0x24dc0a66 | 1teDcTex9Nni8ZVJf41ok7LiXY3yhPzpJS |
| 0x260cca3f | 1teDcRh155jVNfG7KWHnfNL335F8ezzqY9 |
| 0x265173a5 | 1teDc687W6uo7emVHYrcDrM61TXpHNRbkz |
| 0x267d9260 | 1teDcRRGjHWooTcgRKFEYCmxprM3RHRXHo |
| 0x26fe1450 | 1teDcteLX7YrMkRHPJhZ565weCFDrXQVHD |
+------------+------------------------------------+
| 0x1c2bdafd | 1EYFq6QhkHFpYbbughhyDzngMq5t6y1DfN |
| 0x1d46f81e | 1EYFqaSdR48LfoN4ZtnDhbcWy6WyRXA4z5 |
| 0x1d88b07c | 1EYFq79ft3nMqnJPtZNP39awfKoG9rLG4c |
| 0x1e667f78 | 1EYFq3BGaXyAdK7AevRtcXpFh6xuAjYA1U |
| 0x1ea69c06 | 1EYFqWYeHhTtpLACqnv3yCkaYFGmJvLfE9 |
| 0x1ee35ff3 | 1EYFqf3ot5nY1q7gfCEPP5pL3VEtBEN1wy | exchange cold address
| 0x1f024e1f | 1EYFqarZ73DCWdXNPtv5kwztZSSr7RTnBE |
| 0x1f12bd84 | 1EYFqExgy6PKVjjTKogYbx32BwJ36n8oSZ |
| 0x1f2d992f | 1EYFqAUykZu369Xkx3VJUZNcKpRTRNQWhW |
| 0x1f52bf55 | 1EYFqfuzVfeUgNggqauLDrEmV8trn25NRw |
+------------+------------------------------------+
I wonder, if future versions would allow importing 32-bit seeds, and hacking into different wallets.

By the way: in the past, some people lost real coins, by using weak seeds, so your code refers to things, which really happened.

Challenge for readers: find my seed in this game: 1dZKFvMVd9B8wqezG4BdjqPceReEbAMdra (hint: it is a brainwallet, not a randomly-generated thing; but of course you can bruteforce it, if you have no clue).

Edit: I think I have a name for OP_CHECKSIG, if you will ever want to implement Script: OP_CHECKSEED. It should verify, that the transaction creator knows the seed, without revealing it explicitly, like I did. Now, I will try to explore, how seeds are picked, so maybe you could use them as public keys, and pick something else as a private key. I also wonder, how signatures should look like.

Edit:
Quote
Fun little tangent — There are "secret commands" in the console that'll do stuff in the game, but are completely impossible to decrypt from the source code.
As far as I know, there are two secret commands: one is "p2pcurrency", and another one is what we are supposed to guess. I think I know the command to the first secret, but for unknown reason, it shows just some Unicode garbage, instead of showing some meaningful message, like "p2pcurrency" does.

So, should I dig deeper, and try to write some code, to decrypt that Unicode garbage, or is it just a bug, which should be fixed?
Code:
await decrypt_aes(SECRETS[1],await sha256("p2pcurrency"))
"<comment>The Times 03/Jan/2009 Chancellor on brink of second bailout for banks<br><br>In a world where trust is a liability, consensus is power.<br>Thank you, Satoshi.</comment>"
await decrypt_aes(SECRETS[0],await sha256("p2pcurrency"))
Uncaught (in promise) DOMException: The operation failed for an operation-specific reason
await decrypt_aes(SECRETS[0],await sha256(easy_to_guess_secret))
//some unicode garbage goes here
Is it a bug, or a feature?

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 26, 2025, 01:02:03 AM
Merited by stwenhao (1)
 #49

Now I can generate addresses, based on seeds. There are only 2^32 possible combinations, so now I know, how exchange addresses were generated:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I also reached vanity address generator. However, it requires real Proof of Work, so it takes some effort, to mine addresses with given prefixes:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I wonder, if future versions would allow importing 32-bit seeds, and hacking into different wallets.

By the way: in the past, some people lost real coins, by using weak seeds, so your code refers to things, which really happened.
Very amusing! Perhaps I should increase the range of seeds to allow for some more creativity. But yes, I do indeed plan on adding functionality to create wallets with mnemonic seed phrases (in-game BIP39 update), brainwallets, stealing funds, all of the above. I really want to emphasise private key storage security as well, e.g., if you click on a strange link, you might get a virus which will steal your keys from storage or memory, so even in the game it's safer to write down your seed phrases in real life, or buy a hardware wallet in the game.


Edit: I think I have a name for OP_CHECKSIG, if you will ever want to implement Script: OP_CHECKSEED. It should verify, that the transaction creator knows the seed, without revealing it explicitly, like I did. Now, I will try to explore, how seeds are picked, so maybe you could use them as public keys, and pick something else as a private key. I also wonder, how signatures should look like.
My initial idea, which I temporarily discarded for simplicity, was to have gen_privkey(seed) -> gen_pubkey(privkey), whenever generated, the game will store these keypairs internally. For signatures, I can just write a gen_sig(privkey, data), where in the game's db, each signature is referenced as "belonging" to a private key/data pair.

Since the player is the only entity we need to worry about being able to sign and spend transactions, OP_CHECKSIG could be as simple as "what private key was this signature generated from, is the data correct, and does that private key generate the public key". From an educational/realism standpoint, I think it would fake ECDSA well enough  Wink Cheating isn't really something I'll bother to do anything about right now, it's a singleplayer game and really it's the player's choice if they want to cheat etc. In a multiplayer setting, you would obviously have to use actual cryptography libraries, but I can keep it simpler for now.

As far as I know, there are two secret commands: one is "p2pcurrency", and another one is what we are supposed to guess. I think I know the command to the first secret, but for unknown reason, it shows just some Unicode garbage, instead of showing some meaningful message, like "p2pcurrency" does.

So, should I dig deeper, and try to write some code, to decrypt that Unicode garbage, or is it just a bug, which should be fixed?
That's really strange... no, that is not intentional, if you get it right (and enter it in the SATMiner console) it should show up as legible text, not unicode garbage.
If you get it wrong, it should not output anything, it should throw an error along the lines of an "Operation failure. I guess it depends on what browser you're using - if you maybe want to PM with your browser and the command that you tried, I'll try to see if I can recreate it and find out what the problem is.

Just a heads up though, the first secret is just a stupid in-joke between me and some of my friends  Cheesy I'll add a lot more actually interesting secrets down the line.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 26, 2025, 04:21:11 AM
Merited by askii (1)
 #50

New record achieved: 5321 blocks. But then, the network seems to be stuck for some reason (while my own minority chain is still going forward). I will leave it running, and see, if it will just move forward, or if it is really stuck, and will my fork produce more blocks (even if chainwork will be lower).

Current chainwork:
Code:
user@st> block 0000000000000000000036ea7e48a6eb87d12924fac5f89ae42ce5dc0fdecb42
{
  "version": 1,
  "hash": "0000000000000000000036ea7e48a6eb87d12924fac5f89ae42ce5dc0fdecb42",
  "height": 5321,
  "confirmations": 1,
  "time": 1231073167,
  "prev_hash": "000000000000000000000c830d7992039735cc3dacceb776926e3a97978f409a",
  "chain_work": "0000000000000000000000000000000000000000001da5d7d629256838dcd33d",
  "target": "17082528",
  "nonce": 519477280,
  "merkle_root": "d6b7df6161d7c7c54b1cd7f9a3dd465d9d1bcf9447b29b38e49aa7164df49a58"
}

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
May 26, 2025, 10:46:48 AM
Last edit: May 27, 2025, 11:52:02 PM by askii
Merited by stwenhao (1)
 #51

New record achieved: 5321 blocks. But then, the network seems to be stuck for some reason (while my own minority chain is still going forward). I will leave it running, and see, if it will just move forward, or if it is really stuck, and will my fork produce more blocks (even if chainwork will be lower).
Current chainwork:
Code:
user@st> block 0000000000000000000036ea7e48a6eb87d12924fac5f89ae42ce5dc0fdecb42
{
  "version": 1,
  "hash": "0000000000000000000036ea7e48a6eb87d12924fac5f89ae42ce5dc0fdecb42",
  "height": 5321,
  "confirmations": 1,
  "time": 1231073167,
  "prev_hash": "000000000000000000000c830d7992039735cc3dacceb776926e3a97978f409a",
  "chain_work": "0000000000000000000000000000000000000000001da5d7d629256838dcd33d",
  "target": "17082528",
  "nonce": 519477280,
  "merkle_root": "d6b7df6161d7c7c54b1cd7f9a3dd465d9d1bcf9447b29b38e49aa7164df49a58"
}
Sick! But I guess I was wrong about fixing that integer precision bug... The problem is the integers involved in calculating the probability of network finding a block get so big that the fraction loses all precision always equals 0, so basically there is a 0% chance the network can solve a block and progress halts. I've switched it to now use the decimal.js library for high precision fractions, I'll just leave an instance running overnight to check if that fixes it.


Edit: Yes, it looks like it has been fixed.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
May 31, 2025, 06:12:34 AM
Last edit: June 01, 2025, 08:41:58 PM by stwenhao
Merited by askii (1)
 #52


Quote
there is a 0% chance the network can solve a block and progress halts
It seems, that it was not the case. My instance was still running in the background, and successfully reached block number 11762, without your fixes (I guess JavaScript is not reloaded, as long as I won't press F5).

Also, as you can see, I have a minority fork with 11616 blocks. Which means, that there are two chains: one is made by the original network with 371.10 ZH/s, and another one is made only by me, with 7.00 MH/s. It is based on the same Genesis Block, as it was the case in the original Gavin's testnet, before it was changed.

My plan is to see, if the official network can halt. I also wonder, if your chain is compatible with BIP-42: https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki

Because in the original code, after 64 halvings, the network started again with 50 coins. It was fixed by BIP-42, and I wonder, how your network will behave after 64th halving, and even if it can reach it without halting.

Also, I think some kind of "save" button will be needed, sooner or later, because then, it would be easier to restore the state of the network. Another feature I think about is "pruning". Because currently, everything lives in a memory. And if I could save some blocks on disk, and detach it from RAM, then it could be possible to test thousands of blocks, without killing my browser. Or even: pruning alone, without saving things, is also an option, to test some edge cases, like "no new nodes can join, because nobody has the full history anymore, and everyone switched to pruning".

The current chainwork:
Code:
user@st> block 00000000000000000000a1c6fddb84ce51cda1186b4efe949f72ded94e38c281
{
  "version": 1,
  "hash": "00000000000000000000a1c6fddb84ce51cda1186b4efe949f72ded94e38c281",
  "height": 11762,
  "confirmations": 2,
  "time": 1231186150,
  "prev_hash": "00000000000000000000d3e5efaa387c7c80b2d99b8696c50779e5232cd92878",
  "chain_work": "000000000000000000000000000000000000000014ba9dcdc41f70d3d7b2c841",
  "target": "167c01e4",
  "nonce": 914465626,
  "merkle_root": "67739709a23396660cb932a84d7691ae4a0f17318fadbb2e7b7102fadf33a3d3"
}
And some minor UI things: when the price per coin is around 2.7 million dollars, it is no longer fully visible in charts. Also, charts seems to be in the future, because I have transactions from Jan 5, while I can see Jan 7 on the exchange.

​Edit: Custom secrets unlocked:
Code:
await encrypt_aes("<comment>stwenhao: Now I can make my own secrets!</comment>",await sha256('stwenhao'))
Array(75) [ 70, 226, 192, 193, 39, 154, 126, 71, 112, 129, ... ]
SECRETS.push([70,226,192,193,39,154,126,71,112,129,180,132,226,181,21,137,229,145,196,116,207,60,99,201,27,15,156,229,195,221,255,63,152,11,214,145,7,230,61,174,176,26,247,180,212,249,188,143,62,154,81,6,149,67,20,3,206,65,53,12,4,33,55,22,101,172,225,215,174,117,33,23,243,215,97])
And now, I can see this:
Code:
user@st> stwenhao
stwenhao: Now I can make my own secrets!
Which means, that users can also use "encrypt_aes" and "decrypt_aes" for encrypting and decrypting messages. And I guess, as long as everything is single player, you can just use things like that for any kind of encryption, including for example transaction signatures. Also, I guess if you will implement forum and private messages, then such things can be useful, to hide some things from the player, until they will appear in the story.

Edit: Maybe guessing 32-bit seed will be too hard for the beginning. I guess I should port transaction puzzle instead. Let's see, how it could look like:
Code:
+------------+------------+------------------------------------+
| seed_begin | seed_end   | address                            |
+------------+------------+------------------------------------+
| 0x00000001 | 0x00000001 | 1N5ph9XYotdbe8sfN7ReiRetS5bxNXcoGP |
| 0x00000002 | 0x00000003 | 1ZyLAQj2QmX77eV8E6iMj1SbJBqPTQWEPr |
| 0x00000004 | 0x00000007 | 1tyBPPrDRy9hi9NpHJj9A1Ssbkm8R2GHwq |
| 0x00000008 | 0x0000000f | 1rWXov7oBpZKeCRcMfF33Zi3iZw7za5Hn4 |
| 0x00000010 | 0x0000001f | 1JkAcYfowVaDwuVSLMRaZjGeEkWP13cx1U |
| 0x00000020 | 0x0000003f | 1XjB3sq2LSeX1bVoJ9wKaYamvthS2928Ti |
| 0x00000040 | 0x0000007f | 1kBDm7yR84BFBeWij8BfL2PdKJmHCwvL8Z |
| 0x00000080 | 0x000000ff | 1J5y3bkPJEARRJBpTnryyhBj1dwXxDvi9a |
| 0x00000100 | 0x000001ff | 1DJ6SLJfx4qYifQpjMx8BPRBMw6tm1Xzhs |
| 0x00000200 | 0x000003ff | 1H1fCVxu2fdvDjwHmcMMNkWbUf2pcUy3UN |
| 0x00000400 | 0x000007ff | 1BXCT9ci4dF1CAFj2kivAzKQftQpsFALgq |
| 0x00000800 | 0x00000fff | 1SRsoeBP3Ri8ucFLCSt6BW5XGNVx5K52hQ |
| 0x00001000 | 0x00001fff | 1Kx2MoiqwVB2x9o9Gd37CEM7CDcR4kmnT7 |
| 0x00002000 | 0x00003fff | 12xzLssaWbC6M4kN1K5FiDrZ4HwZr3jwwp |
| 0x00004000 | 0x00007fff | 1vG4NpboHxnf35m26Tbtymjf9yYj17nACi |
| 0x00008000 | 0x0000ffff | 17hMrgdaoKaY5uxe1g8nt2McEsW8jNE8MA |
| 0x00010000 | 0x0001ffff | 1otHenypTcx8vVSAwmjcTCnYQxFhM38P95 |
| 0x00020000 | 0x0003ffff | 1kcBgCBzpSJCme3fY38RWM3DLtwKQszfHT |
| 0x00040000 | 0x0007ffff | 17cQRgb8PLFPh6gyiYkwQjwsfx9UCBVjnE |
| 0x00080000 | 0x000fffff | 1zTYApoFF6gEnQjBV6b9UztrHzCGdXMq2K |
| 0x00100000 | 0x001fffff | 1acAk4rwZbE1kQdcTSK55hAKBgYCDP1zLT |
| 0x00200000 | 0x003fffff | 1VptmU7QQppbjEL3LnWR7W54NuXjSRBfzi |
| 0x00400000 | 0x007fffff | 1ZnT2Z8eB3TVgFbbAQHHxuQDAmbD6aPKwv |
| 0x00800000 | 0x00ffffff | 1nAh5FvaEB93CYAQDmjri63ikNH3bggGgY |
| 0x01000000 | 0x01ffffff | 1sb4iLCiF2sezeHicpy2SSJArLP1HCeZ1L |
| 0x02000000 | 0x03ffffff | 1eUvspVKYNe41u8f1D56wRybk98z5DAzxM |
| 0x04000000 | 0x07ffffff | 1z73ewKCxNxPrXqcfNM5b9BReXMXPU7Wm1 |
| 0x08000000 | 0x0fffffff | 1tUzhqwCRZ7WQbe6a359fYVZmpYQjDv3P7 |
| 0x10000000 | 0x1fffffff | 1RXgMtz6hYGYJNrySueYBfZPaUhn4ieMHc |
| 0x20000000 | 0x3fffffff | 1L1wNzycsdKSnZGdB97Ri4YxE7dAeqJNTA |
| 0x40000000 | 0x7fffffff | 1QD852RQMrky4YhSZ8ZYVuHWB1yMC6RQgN |
| 0x80000000 | 0xffffffff | 1uTiu8DSPLvapKe4boQcH3aWJVzJfwRKB4 |
+------------+------------+------------------------------------+
And then, I wonder, what should be done with 1PrgVmwXevXBVbWhwfjeKMEUtxCi3sqLL6, which is generated from zero seed. In ECDSA, valid private keys are in range from 1 to N-1, where N is a 256-bit prime in secp256k1, so here it should be probably some 32-bit prime.

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
June 02, 2025, 01:43:32 AM
Merited by stwenhao (1)
 #53

My plan is to see, if the official network can halt. I also wonder, if your chain is compatible with BIP-42: https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki

Because in the original code, after 64 halvings, the network started again with 50 coins. It was fixed by BIP-42, and I wonder, how your network will behave after 64th halving, and even if it can reach it without halting.
BIP-42 always makes me laugh every time I read it  Cheesy
But yeah it won't restart or overflow or do anything funky like that, the code for halvings is pretty simple:

Code:
let halvings = Math.floor(tip.height / chain_params.halving_interval);
return Math.floor(chain_params.subsidy_base / Math.pow(2,  halvings));
Javascript handles this nicely and block rewards will stay at zero after the last halving. You can verify for yourself by trying it in a JS console:

Code:
let halvings = Math.floor(100000000000000000000000000000000000 / 500);
console.log(Math.floor(5000000000 / Math.pow(2,  halvings)));


Also, I think some kind of "save" button will be needed, sooner or later, because then, it would be easier to restore the state of the network. Another feature I think about is "pruning". Because currently, everything lives in a memory. And if I could save some blocks on disk, and detach it from RAM, then it could be possible to test thousands of blocks, without killing my browser. Or even: pruning alone, without saving things, is also an option, to test some edge cases, like "no new nodes can join, because nobody has the full history anymore, and everyone switched to pruning".

And some minor UI things: when the price per coin is around 2.7 million dollars, it is no longer fully visible in charts. Also, charts seems to be in the future, because I have transactions from Jan 5, while I can see Jan 7 on the exchange.
I'll be releasing a major update sometime soon with more content, alongside that will be saving and other fixes.


​Edit: Custom secrets unlocked:
Code:
await encrypt_aes("<comment>stwenhao: Now I can make my own secrets!</comment>",await sha256('stwenhao'))
Array(75) [ 70, 226, 192, 193, 39, 154, 126, 71, 112, 129, ... ]
SECRETS.push([70,226,192,193,39,154,126,71,112,129,180,132,226,181,21,137,229,145,196,116,207,60,99,201,27,15,156,229,195,221,255,63,152,11,214,145,7,230,61,174,176,26,247,180,212,249,188,143,62,154,81,6,149,67,20,3,206,65,53,12,4,33,55,22,101,172,225,215,174,117,33,23,243,215,97])
And now, I can see this:
Code:
user@st> stwenhao
stwenhao: Now I can make my own secrets!
Which means, that users can also use "encrypt_aes" and "decrypt_aes" for encrypting and decrypting messages. And I guess, as long as everything is single player, you can just use things like that for any kind of encryption, including for example transaction signatures. Also, I guess if you will implement forum and private messages, then such things can be useful, to hide some things from the player, until they will appear in the story.
Nice! Yeah, it could be good for cheat prevention, my only concern really is overcomplicating my codebase and making it too messy for myself with a bunch of AES blobs and hidden keys. I think you're the only person that is exploring the game to this extent anyway  Grin

I'll give it some thought, but it's probably a future problem.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
June 02, 2025, 03:28:53 AM
Merited by askii (1)
 #54

Quote
I think you're the only person that is exploring the game to this extent anyway
Yeah, if all effort will only block me, and nobody else would even try to reveal any secrets, then everything can be done in plaintext as well. Maybe hiding features behind HTML comments is sufficient, as it is now the case with forum, and some other stuff, like more powerful miners.

Also I wonder: is there any place, where people can read the full source code, or submit their pull requests? And which license you picked for that? MIT or something else? Or maybe it is just some hosting, with a bunch of JavaScript files, and you don't use any version control system like Git?

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
June 02, 2025, 04:39:45 AM
Merited by garlonicon (1), vjudeu (1), stwenhao (1)
 #55

Also I wonder: is there any place, where people can read the full source code, or submit their pull requests? And which license you picked for that? MIT or something else? Or maybe it is just some hosting, with a bunch of JavaScript files, and you don't use any version control system like Git?
As much as I love open source software (and I really appreciate your enthusiasm Grin), I am interested in monetising this game (like on Steam, or through purchase on my website) down the line and so I will keep the code closed source.
That said, you’re totally welcome to peek under the hood, prod through it, read what is there and experiment however you'd like, however, I do respectfully ask that nobody copies, distributes or modifies it.

If I ever decide to open up parts of the project in the future, I’ll be sure to announce it properly.

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
June 02, 2025, 07:27:00 PM
Merited by askii (1)
 #56


Finally got all coins in the game. The limit is 49999.99994500 SAT. But now I wonder, why the Genesis Block didn't take 50 coins as unspendable forever?

Current chainwork:
Code:
user@st> block 0000000000000000000a4d303ce63a956ec7ea536337a3b9bb49a30d1d6ffe47
{
  "version": 1,
  "hash": "0000000000000000000a4d303ce63a956ec7ea536337a3b9bb49a30d1d6ffe47",
  "height": 16502,
  "confirmations": 1,
  "time": 1231259515,
  "prev_hash": "000000000000000000043ec69dc24869bad0c60461fe7c7a0395c2f9d9f2848c",
  "chain_work": "00000000000000000000000000000000000000003059494054622e495d0987c1",
  "target": "1706bf5d",
  "nonce": 1997155753,
  "merkle_root": "4024d142e9eaafa61d92979bb4019925a83ef69169eab1e3f34b42a1cc7ee059"
}
I guess I should experiment a little bit with the format of transactions and blocks, to reach some limits, like uint256 overflow. But anyway, I didn't expect to reach 2^96 chainwork. In general, when there will be 2^128 chainwork at any point in time, then it would mean, that the network produced enough power for a single SHA-256 collision, and then hash function should be upgraded.

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
June 03, 2025, 01:00:57 AM
 #57

Finally got all coins in the game. The limit is 49999.99994500 SAT. But now I wonder, why the Genesis Block didn't take 50 coins as unspendable forever?
Ah, the genesis coins are unspendable, there was just an off by one error in calculating the block subsidies, e.g. a new coinbase would receive subsidy at height - 1 which caused an extra 50 coins to be created in one of the halvings (I'll add this fix as part of the update later)

I guess I should experiment a little bit with the format of transactions and blocks, to reach some limits, like uint256 overflow. But anyway, I didn't expect to reach 2^96 chainwork. In general, when there will be 2^128 chainwork at any point in time, then it would mean, that the network produced enough power for a single SHA-256 collision, and then hash function should be upgraded.
I think in an accelerated mini simulation like this, that amount of cumulative chainwork is pretty reasonable. I expect that by its last halving, Bitcoin will probably have an even higher chainwork, so the simulation is probably even a little conservative  Grin

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
June 08, 2025, 06:00:17 PM
Last edit: June 08, 2025, 06:33:57 PM by stwenhao
Merited by askii (1)
 #58

Code:
gen_hash256(7,1,0) "0000000ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(6,1,0) "0000008ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(5,1,0) "00000f8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(4,1,0) "0000cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(3,1,0) "0007cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(2,1,0) "00a7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(1,1,0) "0da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(0,1,0) "6da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
Oh, so that's how hashes are made!
Code:
gen_hash256(0,1,0x00000000) "6da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(0,1,0xffffffff) "ef4ac5a4b4aed0339758c8af0811423763b64e534c85cc2d9c6ef3fbab87dcff"
There are only 2^32 possible outcomes, and everything is simply masked, to get the final value. Nice!

Quote
Perhaps I should increase the range of seeds to allow for some more creativity.
I think the fact, that your system has 32-bit entropy in practice, should be preserved. It makes it much easier to hack into the system, and user perception is still quite good, because making a collision will require checking 2^16 elements, and preimages would still require grinding 2^32 values.

Which means, that not only it is possible to hack into wallets, by guessing 32-bit seeds. It is also possible to hack into block hashes, in a very similar way. And if you spread the same seeds in different places in the code, then all of them are hackable. But: for a single player, maybe it should be considered a feature, and not a bug, for example because then, it is possible to test SHA-256 collisions or preimages, while checking only 2^16 or 2^32 hashes. Nice!

By the way, that also means, that after mining around 64k blocks, there would be block hash collisions! I wonder, if some things would crash because of that, or not. For example: what if there would be two or more block hashes, generated out of the same seeds? How getting block by hash would behave?

Edit:
Code:
for(var i=0;i<10000;++i) cb_P2PK("1teDcUjNzJdjiBesXDfsSUeeQUQYLQdQ5M")
Whoops! 500k coins generated just like that? Well, it seems the supply is no longer limited to 50k coins, if such things are possible.

After Value Overflow Incident, more checks were put in place. In general, no transaction should be able to send more coins than MAX_MONEY (which is 21 million coins in BTC, but could be 50k coins in SAT). Also, making a single output like that should be disallowed, as well as sending more coins than that in a single block. But, as you can easily see, the source of this bug leads to the simple fact, that coinbase amount is never checked anywhere, so it is trivially hackable. I wonder, if it should be that easy, it is single player by the way, so maybe it should be allowed? I don't know.

askii (OP)
Jr. Member
*
Offline Offline

Activity: 44
Merit: 95

better with code than with words


View Profile WWW
June 09, 2025, 12:55:47 AM
Merited by stwenhao (1)
 #59

Code:
gen_hash256(7,1,0) "0000000ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(6,1,0) "0000008ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(5,1,0) "00000f8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(4,1,0) "0000cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(3,1,0) "0007cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(2,1,0) "00a7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(1,1,0) "0da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(0,1,0) "6da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
Oh, so that's how hashes are made!
Code:
gen_hash256(0,1,0x00000000) "6da7cf8ae82798beaba5537ef3b0dd551fef80af1e0239f061f33248589d801c"
gen_hash256(0,1,0xffffffff) "ef4ac5a4b4aed0339758c8af0811423763b64e534c85cc2d9c6ef3fbab87dcff"
There are only 2^32 possible outcomes, and everything is simply masked, to get the final value. Nice!

Yep, that function is the core of how "faking" the proof of work hashes is done. Internally, the parameters are essentially bias (the number of leading zeroes), odds, seed. The function will then sample a hash using the seed from a distribution where the expected value of bias is 1/odds. It sounds a little complicated, but you can get a visual idea by using the sample_distribution(bias, odds, n_samples) function that's already in there. For example:



You can see that the number of hashes generated with 10 leading zeroes was 1074/100000, which is roughly 1% (equal to 1/odds) and it has a somewhat realistic/nice overall distribution.  That is what is actually going on when you buy devices and increase your hashrate, the game just tweaks your bias/odds values in such a way that your hashes line up with the hashes you should be generating if you actually had that hashrate.

By the way, that also means, that after mining around 64k blocks, there would be block hash collisions! I wonder, if some things would crash because of that, or not. For example: what if there would be two or more block hashes, generated out of the same seeds? How getting block by hash would behave?
I haven't tested that, it would take too long  Grin. However, finding a block by it's hash is done by searching downwards from the set of chaintips, meaning if two blocks have the same hash, it'll retrieve the one most recently added to the chain. Theoretically nothing else should actually break since blocks are usually identified by their actual BlockNode object in the JS and not their hash, but I'll have to test it at some point.

Edit:
Code:
for(var i=0;i<10000;++i) cb_P2PK("1teDcUjNzJdjiBesXDfsSUeeQUQYLQdQ5M")
Whoops! 500k coins generated just like that? Well, it seems the supply is no longer limited to 50k coins, if such things are possible.

After Value Overflow Incident, more checks were put in place. In general, no transaction should be able to send more coins than MAX_MONEY (which is 21 million coins in BTC, but could be 50k coins in SAT). Also, making a single output like that should be disallowed, as well as sending more coins than that in a single block. But, as you can easily see, the source of this bug leads to the simple fact, that coinbase amount is never checked anywhere, so it is trivially hackable. I wonder, if it should be that easy, it is single player by the way, so maybe it should be allowed? I don't know.
Indeed, since the game never allows for more than one coinbase transaction to exist in a block, I didn't place a check to explicitly prevent it. I think it's mostly fine, games like Cookie Clicker are also trivially hackable like this. Cookie Clicker actually has messages that you will see if you open the console, such as the following:

Code:
[=== About to cheat in some cookies or just checking for bugs? ===]

or

[=== Hey, Orteil here. Cheated cookies taste awful... or do they? ===]

Maybe I'll just add something like that as a light hearted deterrent  Cheesy

proofofwork.gg (https://proofofwork.gg)   |  Bitcointalk Topic (https://bitcointalk.org/index.php?topic=5538065.0)
stwenhao
Sr. Member
****
Offline Offline

Activity: 269
Merit: 490


View Profile
June 15, 2025, 11:37:03 AM
Merited by askii (1)
 #60

There are three interesting constants used in "split_mix32" function: 0x9e3779b9, 0x21f0aaad and 0x735a2d97. I wonder, how exactly they were created. For the first one, I have some clue:
Code:
0x9e3779b9 * 0x19e3779b9 =  0xfffffffee35e67b1
0x9e3779ba * 0x19e3779ba = 0x1000000011fcd5b24
But for the rest, I have no idea.

Pages: « 1 2 [3] 4 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!