Very Secure

Scheduled Defibrillation For The Jalopy That is TRB

January 5th, 2021

A couple of months ago I was unable to start my car. So I used a trick a mechanic taught me - I opened the hood and banged on the starter with a hammer. I then turned the key in the ignition, but the car still wouldn't start. I tried again, this time banging on the starter harder. And voila, it worked. I had to do this routine of banging on the starter with a hammer1 every time i wanted to use my car. But eventually something got bumped into the right position, I guess, because I no longer have to do this absurd routine to start my car.

It seems that the same type of bang-it-till-it-works approach is required to get trb running. I have restarted my node countless times in order to get it unstuck during the sync process. So I'm posting an example shell script that kills and then restarts trb's bitcoind.2 With the current state of trb, a script like this running on a crontask every 24 hours seems ~required to get sync'd in a timely fashion.3

restart_trb.sh

pid=`top -n 1 -b | grep "bitcoind" | awk '{print $1}';`
echo "killing bitcoind with pid $pid";
kill $pid;
echo "sleeping 60s";
sleep 60;
echo "force killing bitcoind"
kill -9 $pid;
sleep 60;
echo "sleeping another 30s";
# Change IPs and home path accordingly.
LC_ALL=C /your/raw/path/to/bitcoind -daemon -logtimestamps -myip=205.134.172.28 -connect=205.134.172.27 -connect=54.39.156.17 -connect=143.202.160.10 -verifyall &

The script works as follows. First it snags the pid of the process by piping the results from top into grep. If bitcoind is not running then the $pid variable is going to be empty and the following kill commands will fail. Otherwise, as per asciilifeform's advice, the script first does a normal kill to the bitcoind process. This should shutdown bitcoind "gracefully" so that there is no interrupted write to the db, or what have you. However, normal kill's often fail to stop bitcoind, so the script follows up with a kill -9. Finally, the script starts trb.

A potential improvement to this script would be to add some code that handles a corrupted db.

  1. the starter starter! []
  2. You have to change the last line that starts trb to meet the requirements of your specific environment. []
  3. aka less than three months. []

Breathing While Surfing

December 27th, 2020

Hold downs in surfing are much shorter than they feel. When the waves are < 10 feet, the max amount of time you're going to be tumbling underwater is ~10 seconds. The body can easily go without oxygen for 3, maybe 4, minutes. Knowing this helps me relax when I go through the washing machine. After I fall on a wave I try to always place my arms so that they protect my head1 and I relax the rest of my body as I wait for the turbulence to stop. It's not worth wasting my energy thrashing around before the wave's energy has dissipated.

Since hold downs are quite short, you can control your breath so that at no point during a surf session do you stop breathing. Instead, you just time your breaths so that you are exhaling when you go under the water. This requires a little bit of on-land yoga training, you need to be able to do inhalations and exhalations that last 15 seconds. To do this I breathe through the nose. while focusing on controlled contraction and relaxation of the diaphragm. Then, while surfing, I try to finish a deep breath before duck-diving or taking off on a wave. I can watch the horizon and adjust the speed of my breath to get the timing right. Concentrating on the breath keeps the mind and body focused and calm.

***

Here are some shots from a recent session in Marbella:

surfbreath-1
surfbreath-2
surfbreath-3
surfbreath-4
surfbreath-5
surfbreath-6
surfbreath-7
surfbreath-8

  1. I bet 85%+ of surfing deaths are from being banged on the head by one's own board. Someone died at Playa Negra three days ago in this manner. I heard he was knocked unconscious from the impact and then drowned. []

Stretching

December 13th, 2020

A person with little to no flexibility training can (usually) stand on their left leg while supporting their right leg on a table such that the two legs form a 90-degree angle. The same person can mirror that action by standing on their right leg and lifting their left leg to a 90-degree angle. So if someone has the range of motion to move each leg individually 90 degrees, then...

Why can't they do a split?

Is it because there is some physical connection between the two legs? Are there muscles, tendons, or ligaments that tie the two legs together so when they simultaneously stretch out their range of motion is limited? No. The reason one can't do a split is neurological, when they attempt to move a muscle or group of muscles past what their nervous system believes to be their maximum range, their muscles start contracting to prevent the stretch. Stretching further requires removing unnecessary muscle contractions, not increasing the length of tissue.1

This is the premise of Pavel Tsatsouline's book, Relax Into Stretch. Mr. Tsatsouline gives a list of different techniques and stretches to "trick" the nervous system into allowing your body to realize its full range of motion. I cannot verify Tsatsouline's claims myself, as I have not yet attempted his methods. But guitar has taught me that learning to relax muscle groups can lead to an incredible increase in performance.

  1. I have seen other sources argue that it is indeed possible to increase the length of tissue, by adding length to muscle fibers via adding "sarcomeres" - the contractile unit of the fiber. The field of sports "science" seems to be wrapped in pseudoscience. I certainly don't know whether Tsatsouline's theory is correct. []

BJJ Training Log 1 - December 11, 2020

December 13th, 2020

In my third class of BJJ1 in CR we did a series of stretches, went over a new technique, and rolled.

I. Stretching

During the warmup Jarrid led a series of stretches, many of which I was unfamiliar with. We did a sequence that involved the wrist. These involved getting into a push-up position and lifting the palm off the ground while keeping the 4 fingers (not the thumb) on the ground. Then we got into a push-up position where the hand was bent so that the fingers pointed towards the toes and the back of the hand was lying on the mat. More advanced students were able to do a pushup from this position.

Injury prevention is paramount in BJJ, improving flexibility is thus a necessity. I have always been stiff - can't bend over with straight legs and touch my toes. Stretching can be worked on outside of the gym, so looks like I'll have to add some yoga to my life.2 From preliminary interwebs searching and advice from my sensei, I have learned that static stretching post-workout, where one tries to extend the range of the stretch upon exhalation, seems to be one of the more effective ways to increase long term range. There is no need (or perhaps even ability) to increase the length of any tissue, stretching is about turning off the nervous system's automatic contraction response when muscles reach their maximum range of motion.

II. Technique

The combat technique we went over is a little involved and has many components, it's not worth it for me to write down the whole sequence. Rather, it's best to note a fundamental that I learned from studying the complicated technique.

While drilling the technique, I was struggling to put pressure on my opponent as I was laying on top of them. Another student, Nacho, taught me an important lesson - when your knees are on the mat while lying on someone the force you are applying to your opponent from your own weight is dramatically reduced. The proper position when on top of someone is to sprawl your legs out wide and rest on your toes and lean forward so that the weight distribution is maximally placed on the opponent.

III. Rolling

I rolled with more energy as I had at least some small idea of what I should be doing during my battles. I found it useful to tie one of my opponent's legs with my two legs, although I am dubious as to how effective this is in general since it's a 2 for 1 trade.

I also came the closest I've ever been to submitting an opponent. I had back control and attempted my first headlock choke. My technique on the choke was poor. I was squeezing my opponent for almost a full minute, but I could not get him to submit. The correct technique (taught to me by Jarrid) is to place the hand of the arm that is wrapped around the opponent's neck on the other arm's bicep, and then place the hand of the non-choking arm on the back of the opponents head. A mnemonic for remembering the technique is to make the "fuck-you" gesture where you slap the hand on a bicep and flex the bicep.3

  1. Brazilian Jiu Jitsu []
  2. There is so much mysticism in yoga that I am allergic to the idea of starting, but I'll put away my preconceptions and try to find out what sub-discipline can help my bendability. I've found what appears to be a good book on the subj - Relax Into Stretching []
  3. I wonder whether this gesture originates from showing an enemy that you know how to choke them. []

Jiu Jitsu

December 10th, 2020

This week I decided to give Jiu Jitsu a shot.

I have tried the martial art once before. About two years ago I messaged an old friend, Tom, asking to catch up. He responded by inviting me to train with him in his gym.

Tom and I use to wrestle as kids. His dad was in the military and into boxing, and was always pushing Tom to develop his fighting skills. I remember Tom would usually get the best of me, and I distinctly remember being punched in the face as he was demoing new boxing gloves.

Given our rivalry and fighting history it was fitting to meet up in a gym. Didn't know what to expect, but I knew Jiu Jitsu was a martial art that has proven itself useful in the UFC.1 Jiu Jitsu is a grappling sport, like wrestling, where no punches or kicks are allowed. The fight goes until time runs out or one contestant is able to force the other one to submission. One usually gets a submission from his opponent by putting him in a choke hold or by putting him in a compromising position where a large joint2 can be broken by applying force with leverage.

What makes Jiu Jitsu interesting is that you can practice sparring with near full commitment while maintaining a lowered risk of injury compared to other martial arts. You can be choked several times in a session, maybe even pass out, and still be able to train the next day. Imagine sparring hard in boxing, where one punch can send you to the hospital and cause permanent brain damage.

In my first session with Tom I discovered that it is thus common in Jiu Jitsu to roll3 several times with various opponents at the end of a class. Awesome. What a rush to fight against Tom and various strangers all the way to "the death." I was smoked in all my rolls, but I left the gym feeling alive.

I've signed up for one month of Jiu Jitsu classes at a local gym. I plan on training three days a week. I have no illusions that Jiu Jitsu will one day save me in some street fight. But perhaps training in Jiu Jitsu will help me build up discipline and lead me to a healthier lifestyle. In any case, despite the disgusting smell of sweat and the physical pain experienced during a roll, it feels great to fight.

  1. The UFC has exposed other martial arts - such as karate - as being ~useless in anything resembling a real fight. []
  2. Attempting to break small joints such as those in the fingers is banned. []
  3. Rolling is the Jiu Jitsu term for sparring. []

The Galileo Complex

December 2nd, 2020

While reading about the psychology of "climate change denial" I came across the idea of a Galileo Complex - a feeling of superiority that comes from holding contrarian beliefs. When one has a Galileo Complex, they necessarily believe that which goes against the Cathedral's Official Truths, just as Galileo did in his time. Share one of those contrarian beliefs at a dinner party, and the Galileo Complex will be fed as one's "statements of logic" are met with "persecution" via others' "emotion-based arguments."

The man with the Galileo Complex walks through the streets with a smug grin, feeling himself above others because he knows truths - USD inflation is more than 2% per annum, bitcoin is sound money, evidence for impending-doom via man-made global warming is poppycock/cherry-picked for political purposes, the risk of death has not changed because of the covid pandemic, taxation is theft, democracy is rule by the mob, updating software does not mean improving software, etc. etc.

I'm guilty of this Galileo Complex myself.1 Even if the stances I hold are true,2 this Galileo shit does not serve me. It only exists to feed the ego lacking of gratification from meaningful accomplishment. In the end what matters is what one has done, not the beliefs they held.

  1. And boy was I more guilty before Diana Coman helped "draw myself out before my eyes" via her younghands project. []
  2. Which in all cases is debatable, I mean if other people are duped all the time then why should I think that I am not being duped as well? []

Drone Tours

October 13th, 2020

My blog has been in a coma, but it shall not die until I do. Why not break the silence with a (maybe not so) far-fetched business idea? A blog is a journal for thoughts, after all.

So the other day my friend mentioned how he simply could not get his mind off of thinking of projects related to drones.1 He reminded me that, while consumer drones are usually controlled by NFC means, drones can be controlled from across the globe.2 This got me thinking that there may be room in this world for a company to provide... drone tours!

The Drone Tour Company would go to various iconic and picturesque sites and setup "drone stations." These stations would consist of a place for the drones to charge and an internet-connected tower that could communicate with drones in a given radius. The Drone Tour Company would provide software for customers that allows them to control a drone located at any one of the various stations. Customers would pay a fee (and a deposit, lest the company lose all its money due to crashed drones) to take a drone for a spin for some allotted amount of time.

Imagine giving yourself a tour through fjords and canyons, over pyramids and volcanoes, and in the sea3 through kelp beds and coral reef - all in a couple of hours from your own home.

  1. The newer models of those little flyin' buggers are pretty nifty. Like bitcoin, drones fall under the category of actually interesting technology (as opposed to any and all "smart" phone apps) that our generation is the first to experience. []
  2. Although long distance droning means having to deal with some 100-300ms lag both when receiving the video feed and giving piloting commands []
  3. There are aquatic drones too! []

Block Explorer Progress - What's Done, What's Next

July 18th, 2020

Block Explorer Progress - What's Done, What's Next

I) What's Done

I've taken jfw's gbw-node and repurposed it to serve as a block explorer. The functions I'm left with after my changes are view-block,1 view-txn-by-hash/view-txn-by-pos,2 view-ancestors/view-descendents,3 view-address4, balance,5 utxos,6 and push.7

Per jfw's suggestion, I merged the input table into the output table in the sql schema. I renamed the output table as output_input. Thinking of the output of one txn and the corresponding input in the txn that spends that output as being a single structure has helped me form a clearer picture of how chains of bitcoin transactions are connected.

Here is a snapshot of the current sql schema with the new "output_input" table.

--- Gales Bitcoin Wallet: node (online component) schema
--- J. Welsh, December 2019
--- Dialect: SQLite (3.7.0 for WAL)                                                                                                                                                                                                          

PRAGMA journal_mode=WAL;
BEGIN;

CREATE TABLE block (
       block_id  INTEGER PRIMARY KEY,
       height    Integer NOT NULL,
       size      INTEGER NOT NULL,
       version   INTEGER NOT NULL,
       prev_hash BLOB NOT NULL,
       hash      BLOB NOT NULL,
       root      BLOB NOT NULL,
       timestamp INTEGER NOT NULL,
       target    INTEGER NOT NULL, -- Should we include this?
       nonce     INTEGER NOT NULL
);
CREATE UNIQUE INDEX i_block_hash on block(hash);
CREATE UNIQUE INDEX i_block_height on block(height);

CREATE TABLE tx (
        tx_id    INTEGER PRIMARY KEY,
        hash     BLOB    NOT NULL,
        block_id INTEGER NOT NULL REFERENCES block,
        pos      INTEGER NOT NULL, --pos in block
        comment  TEXT,
        size     INTEGER NOT NULL,
        fee      INTEGER
);
CREATE INDEX i_tx_hash ON tx(hash);
CREATE UNIQUE INDEX i_tx_block_id_pos ON tx(block_id, pos);

-- Every input begins its life as an output.
CREATE TABLE output_input (
        output_input_id INTEGER PRIMARY KEY,
        creating_tx_id  INTEGER NOT NULL REFERENCES tx,
        out_pos         INTEGER NOT NULL,
        address_id      INTEGER NOT NULL REFERENCES address, -- aka script pub key
        value           INTEGER NOT NULL,
        spending_tx_id  INTEGER REFERENCES tx, -- If null, it hasn't been spent.
        in_pos          INTEGER, -- position in input vector in spending txn
        scriptsig       BLOB,
        flags           TEXT
);
CREATE UNIQUE INDEX i_output_txid_out_pos ON output_input(creating_tx_id, out_pos);
CREATE INDEX        i_output_addrid ON output_input(address_id);
CREATE INDEX i_input_txid_n  ON output_input(spending_tx_id);

CREATE TABLE address (
        address_id INTEGER PRIMARY KEY,
        address    BLOB NOT NULL
);

CREATE UNIQUE INDEX i_address_address ON address(address);

CREATE TABLE state (
        scan_height INTEGER NOT NULL DEFAULT(-1)
);
INSERT INTO state DEFAULT VALUES;

COMMIT;

II. What's Next

A) Refactor commands so that they can be used by both the command line and web interface.

I've decided to use flask to run the web server portion of the block explorer. From reading the logs, this python package appears to be a handy utility whose use is a mortal sin. So I don't want to make flask's installation a requirement for running the block explorer locally.

I plan to do the following. I'm going to design the block explorer so that I can run a public web interface using flask. The source of everything will be public, so anyone will be able to install the block explorer along with flask and use the explorer locally via the web interface. Alternatively, they will be able to install the explorer without flask, but in this case they will only be able to use the block explorer via a command line interface similar to the one gbw-node currently employs.

In order to allow for the two uses of the explorer, I need to split all the command functions into two parts - one that returns structured data8 and the other that prints the structure data. The command line interface and web interface will stringify the data appropriately.9

B) Write a view-raw-hex of block command.

As an exercise in understanding and in order to check the integrity of the explorer's stored data, I want to make sure that I can take the tables in the gbw-node sql database and reconstruct a bit-perfect block.10 In order to provide this feature I need to store some data considered extraneous by the original gbw-node wallet, such as the input field for a coinbase as well as a transaction's sequence number, version, and locktime.

C) Get domain names and configure servers.

I now have one box currently syncing trb on asciilifeform's rack.11 But setting up at least one other mirror in a different geographical location seems prudent.

D) Continous trb scanning.

Currently gbw-node has no way to handle reorgs. It pulls data from the bitcoin rpc up until the 'block height - CONFIRMATION'th12 block. This is done via the command "scan", which halts when it reaches the most recent block. To keep the explorer's data up to date, the block explorer must always be scanning. I can either modify the scan command to run on an infinite loop, sleeping for ~10 mins when it hits the max block height, or I can just continually rescan via a crontask.

E) Provide a way to show information about transactions in the mempool / recent blocks.

The main use cases I have for a block explorer are obtaining utxo data for spending bitcoins, pushing raw bitcoin transactions to the network, and confirming that recently pushed transactions were received by the network. The block explorer in its current state has no way to store transactions in the mempool. The schema requires a transaction to have an associated block id and block position. So currently the block explorer is not useful for showing recent blocks, nor for showing recent unconfirmed transactions.

I plan to create a separate table, mempool_transaction, that displays information about transactions in the mempool. The scan function will delete mempool transactions whenever it finds the transaction successfully placed in a deep block.13 I also will want to figure out how to store recent blocks that may be reorg'd. I think that I'll handle this in a similar manner to mempool_transaction, with some volatile table named recent_blocks. The corresponding row from this table will be deleted when the block has confirmed its place in the explorer's "main chain."

  1. Show's the information from a block's blockheader. []
  2. Both of these functions display the same information for a transaction. But one lets you search for the transaction by providing the block height and the position of the transaction. The other lets you search for a transaction by its hash. []
  3. These two functions return the txn hashes for every single txn in a transaction's ancestor tree, all the way up to the original coinbases, and the descendents of a transaction, all the way down to the current UTXOs, respectively. []
  4. Displays all transactions where the given address either creates or consumes a UTXO. []
  5. Displays the bitcoin-denominated balance of an address []
  6. Displays all the unspent transaction outputs for an address. []
  7. Sends a raw hex txn to the network. []
  8. I think I'll use python's class system, and then create and return immutable objects. []
  9. \n's for command line <b>'s + links for the web interface, etc. []
  10. It also seems prettty basic to me that a block explorer should be able to return a hexadecimal representation of a block, yet afaik none of the heathen ones provide this simple feature. []
  11. It seems like half of the network resides on asciilifeform's shelf... []
  12. Defaulting to 6 confirmations []
  13. I have not yet concluded what I should do with dust transactions that start to fill up the mempool. []

Notes on how to speed up the trb resync process after data corruption

July 14th, 2020

I was syncing my local trb node and I saw this error in my debug.log file:

NSt8ios_base7failureE

My most recent .dat file had been corrupted, from a cause unknown but most likely from my computer powering off during a write operation. I took some notes on how to avoid having to redownload all my hard earned blocks. The commands I've pasted below are specific to my case, but you can use them as an example.

I) Get asciilifeform's blkcut tool.

II) Remove your most recent blk000n.dat file, since it should be the file that is corrupted. Then cut up the remaining blk000*.dat files and organize the individual block files into a directory. How you do that second step is up to you. I moved all the blocks to ~/.bitcoin/cutblocks.

rm ~/.bitcoin/blk0003.dat # corrupted file.
cutblock ~/.bitcoin/blk0001.dat
cutblock ~/.bitcoin/blk0002.dat

mkdir ~/.bitcoin/cutblocks

for i in {0..9}
do
mv blk0001.dat.$i* ~/.bitcoin/cutblocks; mv blk0002.dat.$i* ~/.bitcoin/cutblocks;
done

III) Remove your old .dat files. I put them in a backup folder.

mkdir ~/bitcoin-data-backup
mv ~/.bitcoin/*.dat ~/bitcoin-data-backup

IV) Start bitcoind with the -caneat flag.

LC_ALL=C nohup ./bitcoind -caneat -myip=234.3.12.222 -addnode=108.31.170.3 -addnode=205.134.172.27 -verifyallll 2>&1 &

V) Now we need to run a script to eatblock on all our blocks. First find out how many blocks each old blkdata file had.

cutblock -c ~/bitcoin-data-backup/blk0001.dat

Then we load those blocks with a script to iterate through the eatblock commands. Run the following command replacing 188528 with the number you received from cutblock -c minus one1. If you have more than 1-3 blk000*.dat files, you'll want to create a more sophisticated script.

for i in {0..188528}; do echo "eating block $i"; ~/v/trb054/bitcoin/build/bitcoind eatblock ~/.bitcoin/cutblocks/blk0001.dat.$i.blk; done
  1. The first blk is blk0001.dat.0.blk []

Representing Data - Notes on Big And Little Endian Encodings

July 13th, 2020

While working on my block explorer I realized that my grasp on what it means for a system to be big or little endian was weak at best. I took the time to think about what exactly was the difference between the two. In the process I cleared up confusions in my overall understanding of encodings.

***

At a lower level, data structures in computer programs are all kept as series of bits. The state of these bits are stored on a piece of hardware such as a flash drive, an ssd drive, a mechanical hard drive, a stick of RAM, a CD, a cache, etc. Each bit has some physical location within its storage device. We can abstract this observation and give each location of a bit state a unique numerical address. Ostensibly numerically adjacent addresses map to physically adjacent bits, but this need not be the case.

We are often curious to know the state of the bits on our physical devices. Our goal becomes to bring an invisible state of the world into our field of consciousness. To do this we need our machine to read the bits on its storage device and construct light on our monitor that form characters we can perceive with our eyes. The characters we choose to represent the raw data are usually the same ones we use when we write numbers in hexadecimal: 0123456789ABCDEF. Since there are 16 characters in our symbol system, each character can represent an ordered list of 4 bits. To get a better understanding, we can work through an example.

Here is a mapping of addresses to bit states, with the address written in base 10 and bit state written as a 1 for on and a 0 for off.

0  -> 1
1  -> 0
2  -> 1
3  -> 0
4  -> 1
5  -> 1
6  -> 1
7  -> 0
8  -> 1
9  -> 1
10 -> 0
11 -> 1
12 -> 1
13 -> 1
14 -> 0
15 -> 1

Writing out the 1's and 0's with the lowest address on the left, the above becomes:

1010111011011101

If we want to represent the data above with the hexadecimal characters we do the following. We write out a hexadecimal string such that if we were to convert each hexadecimal character into its 4 digit binary equivilant we would have the bit state of each address, with the leftmost bit being the lowest address (0) and the rightmost bit being the highest address (15)


1010 | 1110 | 1101 | 1101 |
  A  |   E  |   D  |   D  |
AEDD

It's important to understand that so far we are not using the hexadecimal characters nor their 4-digit binary equivilant to represent numbers. These characters are only being used to represent the state of the data as it is stored in some storage device.

However, we do often use the state of chunks of memory to represent numbers. Coming up for a standard for how bit states map to numbers allows one to do arithmetic operations. We could, in theory, come up with any arbitrary mapping. For example, one could make the 5th position in memory represent the most significant bit of a number, then the 0th the 2nd most significant bit, the 9th the 3rd, etc. This would admittedly be a stupid and confusing scheme for representing numbers. In practice there are two prevailing conventions - big endian and little endian.

In a big endian1 system, the bit state at the lowest address represents the most sigificant bit in a binary number and the state in the highest address represents the least significant bit. The physical state of the machine above in a big endian context represents the following number: (I've written the same number 3 times in different bases)

1010111011011101 (base 2)
AEDD (base 16)
44,765 (base 10)

In little endian, the least significant byte is placed at the lowest memory address. However, within that byte, the bit with the lowest address is the most significant.

0  -> 1 (9th  most significant bit)
1  -> 0 (10th most significant bit)
2  -> 1 (11th most significant bit)
3  -> 0 (12th most significant bit)
4  -> 1 (13th most significant bit)
5  -> 1 (14th most significant bit)
6  -> 1 (15th most significant bit)
7  -> 0 (16th most significant bit)
8  -> 1 (1st  most significant bit)
9  -> 1 (2nd  most significant bit)
10 -> 0 (3rd  most significant bit)
11 -> 1 (4th  most significant bit)
12 -> 1 (5th  most significant bit)
13 -> 1 (6th  most significant bit)
14 -> 0 (7th  most significant bit)
15 -> 1 (8th  most significant bit) 

When in the context of little endian, the same above state now represents a different number, again written 3 times in different bases:

1101110110101110 (base 2)
DDAE (base 16)
56,750 (base 10)

If you tell a computer "store 56,750 starting at address 0 for me", the state of the bits at the addresses in memory on a big/little endian machine will differ. But if you give the more specfic instruction "write byte 9F at address 0", then the resulting state will be the same on the two machines.

***

As jfw points out, some fields in trb have the endianness of their internal and external representations swapped. So when you extract the hex characters that represent the "state of the machine" that is storing the block data, you need to (sometimes) reverse the order of the bytes so that the resulting hexadecimal string represents the correct numerical value for the field you're observing.

Creating/finding an exhausitive list of which fields in trb are represented in little endian and which are represented in big endian is on the todo list.

  1. Also known as Network Byte Order, since it is the standard way to organize bits to send accross networks. []