I couldn’t figure out how the SHA -256 hashing function is used in Bitcoin’s proof of work, and also why it is computationally easy to verify but hard to solve for a valid nonce?
The easiest way to figure it out, is to write any implementation of SHA-256 in any programming language. It would take at most few hundreds lines of code, probably less. And then, you will observe exactly, how a given message is turned into its hash.
Some example implementation, where some empty message is hashed:
https://github.com/stwenhao/small_curves/blob/master/sha256.cppIf you don't have any C++ compiler, you can run it online, for example here:
https://www.onlinegdb.com/online_c++_compilerExample online calculator with SHA-256:
https://emn178.github.io/online-tools/sha256.htmlStep-by-step calculator:
https://sha256algorithm.com/i also will like to know the actual role of merkle root in the block header, as how it allows efficient verification of transactions inclusions.
This is how the block header looks like:
https://mempool.space/api/block/000000000000000000001de7b0cafc932a6e092f2160aeb3ba9a9602b0e3c394/headerversion: 0060c522
previous block hash: c8a15d5133b05ed8db59ce711da1836c2baee4de429200000000000000000000
merkle root: 1a78052604f22987120ede93134ad73330a112f3bbf74110ea5bea99feea8ff2
timestamp: 2780116a
difficulty: 790f0217
nonce: 62324994
When you have merkle root, then it is just some 256-bit field. It is calculated once, and then, miners can change version, timestamp, and nonce, while leaving everything else as it is. And then, it doesn't matter, if your block takes 1 kB, or 1 MB: you still hash exactly the same 80-byte block header, every time.
However, if there would be no merkle root, and if you would need to hash the whole block, then, suddenly, mining 1 MB block would be slower, than mining 1 kB block. And then, miners would have an incentive, to make blocks as empty, as they could be. But fortunately, it is not the case.
is it also possible that the miner modifies their block header during the mining process?
Miners have to do that. You need to change something, to make a different hash. This is why nonce is needed in the first place. Early miners changed only their nonces, and when they checked all 2^32 possible values, and didn't find a valid block, then they changed the extra nonce in the coinbase transaction.
Later, it turned out, that changing the block version, or the timestamp, is faster than that. Which is why miners started doing it. Because changing the merkle root is expensive: you need to calculate SHA-256 once again, for a different data. While flipping a bit in the block header directly, is much faster.
how bitcoin difficulty adjustment algorithms work?
It is simply measured, how much time it took, to produce the last 2016 blocks. It should take two weeks. If it took longer, then the difficulty goes down, if it was done faster, then it goes up.
And also how is the new difficulty calculated after every 2016 block
https://github.com/bitcoin/bitcoin/blob/master/src/pow.cpp#L14There is a function "GetNextWorkRequired", which just counts, how long it took to mine the last 2016 blocks, and adjusts it.