Testing Automated Speech Recognition (ASR) and Machine Transcription (MT) Accuracy

Testing Automated Speech Recognition (ASR) and Machine Transcription (MT) Accuracy

machine transcriptions

We recently had the opportunity to test and evaluate (T&E) the accuracy of a machine transcription product in our lab. Two challenges with testing the product were finding a test corpus we could trust and a scoring methodology that was fair.

The problem with finding a trustworthy test corpus was that we had to ensure that every spoken – and misspoken – word was in the transcript. The transcript of each audio file tested had to be word-for-word accurate. We found plenty of translations of audio files, but translations are not transcriptions and would not work for this T&E effort.

The solution to this problem was found in language lessons at the Defense Language Institute Foreign Language Center (DLIFLC), that contained audio samples with exact transcriptions to accompany the lessons.  These lessons gave us plenty of audio with transcriptions in numerous foreign languages.

The problem of scoring the accuracy of machine transcriptions was solved with the use of the Word Error Rate (WER) metric.  The WER accounts for three kinds of errors an MT product might make:

  • Word substitution (S) – substituting an incorrect word or a homophone
  • Word insertion (I) – inserting a word that was not spoken
  • Word deletion (D) – omitting a word that was spoken

Together with the total number of words spoken (N), an error metric was calculated.

 

error metric calculated

Thus, an accuracy measure could be calculated as that allowed the comparison of MT product performance or the performance among different language models in the same product.

To calculate S, D, I, and N the team utilized the sclite utility from NIST.  sclite is a tool specifically designed for scoring ASR and MT outputs.  The tool required the trusted reference files to be in one of three formats for easy comparison: conversation time-marked (CTM), segment time-marked (STM), or transcript format (TRN).  These file formats contain extremely accurate time markings for each word in the reference file.  You can learn more about these file formats and ways to produce them at the sclite homepage.

The test team opted for a slightly easier approach. We discovered that if we removed all punctuation, extraneous spaces, and carriage returns and formatted the reference file on a single line, as a single utterance, the sclite tool aligned correctly and scored the transcript.  We validated this approach by reformatting a few of the STM formatted files provided by the product vendor and were able to reproduce their results within 2%.

This T&E procedure proved to be successful and the preparation of the reference transcript files, the running of the MT product, and the scoring by the sclite tool could be automated. In all, the team tested using four different languages and a total of 480 files.

The approach to obtaining ground truth reference test data and use of an industry standard test tool are just small examples of Armedia’s innovative capabilities in the T&E arena.

Microsoft Azure Face API

Microsoft Azure Face API

Microsoft Azure Cognitive Services Face API

Microsoft Azure is a cloud computing service that has its own machine learning service, known as Cognitive Services. It is split into five categories: Vision, Speech, Language, Knowledge, and Search, with each category containing several tools, for a total of 26. Under Vision, there are six tools: Computer Vision, Content Moderator, Custom Vision Service, Emotion API, Face API, and Video Indexer. As the title suggests, the focus here is on the Face API tool.

The Face API is split into two basic categories:

  • Face Detection – discovers a face in an image, with an ability to identify attributes such as gender, age, pose, facial hair, glasses, and head pose.
  • Face Recognition – takes faces and performs comparisons to determine how well they match. Has four categories –
    • Face Verification – takes two detected faces and attempts to verify that they match
    • Finding Similar Face – takes candidate faces in a set and orders their similarity to a detected face from most similar to least similar
    • Face Grouping – takes a set of unknown faces and divides them into subset groups based on similarity. For a subset of the original set of unknown faces, each face within that subset is considered to be the same person object (based on a threshold value).
    • Face Identification – further explained below.

With Face Identification, you must first create a PersonGroup object. That PersonGroup object contains one or more person objects. Each person object contains one or more images that represent the respective person object. As the number of face images a person object contains increases, so does the identification accuracy.

For example, let’s say that you create a PersonGroup object called “co-workers.” In co-workers, you create person objects, for example, you might create two – “Alice” and “Bob.”  Face images are assigned to their respective person objects. You have now created a database with which to compare a detected face image. An attempt will be made to find out if the detected image is Alice or Bob (or neither), based on a numerical threshold.

This threshold is on a scale that is most permissive at 0 and most restrictive at 1. At 1, they must be perfect matches – by perfect, I mean that two identical images at different compression rates will not be recognized as a match. In contrast, at 0 a match will be returned for the person object with the highest confidence score regardless. In my experiments, somewhere between 0.3 -0.35 tended to strike a good balance. To reiterate an earlier point, more images per person object increases identification accuracy, thus decreasing both false positives and false negatives.

An Example Application to Simulate Video Analysis

An example implementation of Face Identification, in conjunction with Dlib and FFmpeg, follows. The purpose of this application was to identify faces in the video, and since Face Identification only detected still images, FFmpeg was used to extract keyframes for Face Identification to examine individually.

Face Identification detects faces in images before identifying them, but in my experience, Dlib detected faces more accurately and a lot faster. In this case, Dlib detected if an image contained a face; if it did, that image was sent to Azure for face identification. The disadvantage here was that detection was done twice – first in Dlib, then again in Face API. It was faster to detect an image locally using Dlib than it was to call the Face API – which was remote. It was especially advantageous to filter using Dlib when there was a long video with relatively little facial presence (e.g., security footage). If most of the video had a facial presence, disabling Dlib may have been preferable. Another factor to consider is that Azure charges fees based on the number of API calls, so filtering using Dlib first saved money.

Figure 1 depicts the Face Identification user interface.  The three list panes in the middle of the user interface (from left to right) define the PersonGroup objects, the Person objects, and the images attached to each Person.  In the figure, group2 is selected which contains two person objects:  Person_A, and Person_B.  Person A is selected and the list of images associated with Person_A are listed in the right-most column.  Figure 2 discusses the controls and settings for the conducting a face match run.

Azure face recognitionFigure 1 – Highlighted in blue from left to right: PersonGroup, person, face image. The database image selected here is Abraham Lincoln, belonging to Person_A in group2. There can be more than one image per person. If an examined image contains a detected face that sufficiently resembles Person_A (or Person_B), best match found.

Figure 2 – A closer look at this application that implements Azure Face API, FFmpeg, and Dlib

Some points regarding using the above method to analyze video through keyframe extraction:

  • In tests, it was found that the baseline accuracy was comparable to that of other methods tested (AWS Rekognition, Linux face_recognition), see Figure 3. The advantage of this system was that accuracy could be improved by adding multiple face images per person.

Figure 3 – Azure results compared to other facial recognition tools tested

  • The PersonGroup profiles were persistent, using Microsoft Azure’s cloud storage
  • Easy to add/remove/modify groups, people, and face

Limitations:

  • API calls were limited to 10 per second – this is a server-side imposed limitation, and there exists no local workaround (another advantage to using DLib locally)
  • Because of the API call limit set by Microsoft, it was slow relative to other methods
  • Like most facial recognition systems, it was difficult to predict processing time. The two main influencing factors were:
    • File format – this played a much more important role than file size. In fact, a file that was half the size could take longer to process depending on the format.
    • Number of detectable faces in a file – there would be no point in using this if you already knew the contents of a video file, and processing time went up as facial presence increased
  • Internet connectivity is obviously necessary – processing was server-side and there was no option for locally exclusive data storage

It should be noted that Face API was meant to be used to analyze images and live video streams, but not stored video files. This application attempted to simulate the analysis of stored video files, and thus was using the API in a manner for which it wasn’t intended. For example, ensuring that the 10 API calls per second limit wasn’t exceeded required testing, as Azure simply discarded any API calls that exceeded the limit with a generic error message – it did not add the images to a queue to be processed as soon as possible. Frames could be lost that way when examining a series of images. Cognitive Services does offer a Video Indexer that, among other things, has face tracking and identification, but that is only against a celebrity database. The user can’t define the database, so it is highly limited. The Video Indexer is in preview mode, so I suspect that at some point it will allow for a more flexible facial recognition system. Currently, it does not offer what this application was attempting to simulate.

This application was written using C#, although Face API also supports cURL, Java, JavaScript, PHP, Python, and Ruby.

Conclusion

Although Amazon Web Services has a far superior market presence than Microsoft Azure, Microsoft Azure’s Cognitive services is very functional. The accuracy of Face API is comparable to AWS’ facial recognition alternative, albeit a bit slower. Its array of tools is consistently growing in size as well. There is an argument to be made that the advantage to AWS is simply that it has a larger userbase, which alone can increase the functionality of a product through consumer demand and supplier response. If Microsoft has something to prove in the area of machine learning, though, that can be an advantage as well.

The other contenders in this area are the various Linux-based, open-source tools, which are often just as good in terms of accuracy. A huge advantage Linux has is control over the locality of processing, which allows for some creative control when it comes to memory and storage management, along with general application implementation. With the ability to introduce multi-threading, Linux is often the fastest when it comes to processing – you could multi-thread AWS or Azure, but there is no point because their servers do the heavy lifting and decide what you get and when you get it (think back to API call limits). The downside Linux has when compared to Azure and AWS is comprehensive support. AWS and Azure have a centralized customer support system, and Linux by nature does not. It can be a headache to even get to the point of installing the necessary software to begin coding for it, as packages often become out-of-date and don’t always play nice, plus online documentation can be challenging or absent. But that is the tradeoff when it comes to the freedom and control of Linux. Plus, it’s free.

At this point, there is no clear advantage to using one over the other.  However, one thing is for sure – Microsoft Azure and AWS will continue to invest in this space through research and acquisitions to become the preferred provider of artificial intelligence tools and services.

Face Match Face Off

Face Match Face Off

face recognition

Recently, a client stopped by and asked if Armedia had, or knew of any open source, face matching software that could scan a video and determine if a suspect’s face appeared anywhere in the video.

Our team was intrigued.

In today’s world, how available and how accurate was this type of software? This request launched a line of investigation that not only solved our client’s problem but proved to be insightful and rewarding.

A quick Internet search for open source products that could match a probe face in a video produced limited results, so we expanded our search parameters slightly to include low-cost cloud services.  The products we decided to investigate were:

We assigned a developer to each product to prototype a solution, given only the following minimum requirements from our client:

  • The solution shall identify (i.e., indicate time off-sets) all occurrences of a suspect’s face in a video.
  • The solution shall output a CSV file for each suspect indicating in which videos they were detected, and at what time off-sets.
  • The solution shall output a CSV file for each video containing the name and time off-set at which each suspect was identified in the video.
  • The solution shall accept all probe images as a group.
  • The solution shall accept all videos as a group.
  • The solution shall perform better than real-time (i.e., a 5-minute video should be processed in less than 5 minutes).
  • The solution shall have adjustable operating parameters to affect the sensitivity of detection and computer resource usage.

Early in the project, the pyAnnote developer determined that although the accuracy and output format of the pyAnnote software was impressive, it was intolerably slow (roughly 2-3 times real time).  Therefore, she abandoned pyAnnote as a possible solution and moved on to investigate the Python Face Recognition software, taking a different tack than the developer already investigating the same software.

With these broad requirements, developers were free to architect creative solutions. Therefore, each project took on its own character and individual goals.

  • Face to Face – a desktop, Java-based UI, which leveraged Amazon’s Rekognition API in addition to their S2 storage infrastructure. This project could scale as demand required.
  • Azure Multi-Imaged Face Identifier (AMIFI) – a desktop, C#-based UI, which leveraged Microsoft’s Face Cognitive Service. This project could accept multiple samples of a face to build a more comprehensive model of the suspect.
  • Distributed Face Recognition (DFaR) – a massive, enterprise-level solution utilizing multiple servers, GPUs, load balanced queueing, etc. This project leveraged Python Face Recognition had no GUI and was designed to be integrated into a larger forensic process.
  • Face Recognizer – the other project using Python Face Recognition took the opposite approach and built a solution that ran on a laptop with no special hardware or network connections.

The developers and the project managers met weekly for 3 months to demonstrate progress, discuss problems, and to solicit advice from one another.  These meetings were dubbed “face offs” as they took on a tone of friendly competition. The developers went all out to produce the most accurate and fastest performing solution.

Two interesting findings resulted from these collaborative/competitive meetings.

  1. None of these software products could match face images in videos directly. They were designed to compare and match faces in still images.  As a result, all the developers converted the videos into sequential series of still images (i.e., frames) using FFmpeg and compared the frames to the probe image.
  2. The conversion of videos to frames resulted in thousands (sometimes tens of thousands) of JPG files. Often, the majority of these images contained no faces and incurred processing and resource usage penalties unnecessarily.  This was especially the case with cloud solutions where storage and processing incurred real costs.  To address this problem, all of the developers filtered the images using Dlib.  Only the frames in which Dlib indicated a face was present were allowed to pass through the identification process.

Perhaps the most interesting result was that all of these prototypes and underlying technologies achieved nearly the same level of accuracy (see Precision-Recall chart in Figure 1).  Open source, community-driven technology held its own against the technologies developed by the global R&D powerhouse companies.

Although the results were nearly identical, that doesn’t mean they were sound.  Looking at the Precision-Recall chart in Figure 1, you see that the data points cluster around 0.6 precision and 0.45 recall.  This means that 60% of the time the software identified a suspect it was correct, while it only identified 45% of the suspects it was presented.  Ideally, both precision and recall values should be high for an accurate, well-performing solution.

It is important to note that our test videos and real-life videos were low quality, grainy, surveillance videos.  We would expect better results using higher quality videos.

precision-recall chart

Armedia satisfactorily identified 19 suspects in nearly 6,000 surveillance videos with confidence values and time off-sets so manual confirmation could be made.

The Face Match Face Off is a good example of the type of research and development Armedia brings to client engagements. Our team is well versed and well equipped to research, develop, prototype, and deploy technologies in the areas of computer vision, machine learning, big data, signals processing, and computer forensics.  The Face Match Face Off not only solved a real-world problem for our client, it provided them with information about four leading face recognition technologies, enabling more informed decision making in future technology investments.

Blockchain Technology by Example: A Walkthrough of a Simple Blockchain Program Written in Bash

Blockchain Technology by Example: A Walkthrough of a Simple Blockchain Program Written in Bash

blockchain technology

Intro

The purpose of this blog post is to explain how blockchain technology, and in particular a cryptocurrency like Bitcoin, works by example. A simple blockchain bash script, named bashCoin, will be used for illustration.

Digital Currency and Blockchain Overview

A blockchain is a series of files arranged so that when a new file is inserted, it both verifies the previous file and renders it unchangeable. The files (blocks) in the chain are safeguarded from alteration since all files are linked to one another. This proves to be extremely useful for both record retention in a records management system and a trust-less decentralized digital currency.

A digital currency can use a blockchain to create an immutable list of transactions. This means that, under the correct circumstances, once a transaction is saved to a block it cannot be altered or deleted without breaking the chain.

When people need to exchange goods and services they most often use physical currency. Trading a dollar bill for a soda is much easier than trying to figure out for how long a painter would paint the store owner’s house in exchange for the soda if the store owner needed painting at all.  As long as both the painter and the store owner agree that the dollar bill is worth something, they can exchange it instead of bartering.

Instead of physically exchanging something during a monetary transaction, however, participants can simply keep track on a ledger: a running list of financial transactions.  For example, a transaction such as “Alice sends Bob 100 dollars” can be written into a ledger that both Bob and Alice trust.  The transaction information can then be used to calculate how much money both Alice and Bob have at any moment.

If the ledger is shared amongst all users then anyone should be able to submit transactions and calculate how much money anyone has at any moment.  A public ledger setup as a blockchain has the added capability of keeping past transactions secure as well as protecting users from future fraud.  Users are also required to use a public key / private key pair as their account address which they use to encrypt transactions. This encryption prevents participants from writing false transactions to the ledger.

Transactions are grouped into blocks before being added to the blockchain. The frequency at which they are added depends on other users verifying the block through a process called mining.  Mining a block consists of adding a random number (called a nonce) to the block so that when it is hashed the resulting hash starts with a certain number of zeros.  This process is extremely difficult and time-consuming but once the random number has been found, reversing the process to check the answer is simple and quick.  The miner who found the random number that produces a qualifying hash is then rewarded with a predetermined amount of digital currency as well as fees paid by users.  The transaction that pays the miner is listed first in the next block in the ledger.

Mining a block and being financially rewarded is one of the things that give value to the currency. Forcing users to work for the monetary reward makes it so that others that are not mining appreciate their effort and value the currency in circulation.  The reward is automatically given to the miner and it is created as if it were mined out of the Earth.  It was not owned by anyone before the miner and is a finite resource. The financial reward given to miners decreases over time and will eventually reach zero.

To better keep track of the ledger as well as ensuring security, a cryptocurrency such as Bitcoin can use change transactions.  When a user sends another user coins, he or she will send themselves their remaining balance to a brand new address.  The new address is encrypted and unrelated to the address before it.  For example, if Alice has a total of 300 coins and she wants to send Bob 100, she would send Bob 100 coins and send 200 coins to a brand new public/private key pair address.  She would generate this new address when she sends the coins to Bob.  Alice would be the only owner of the new private key.

Genesis

Blocks in the blockchain are assembled with the hash of the previous block.  Starting a blockchain requires a block that does not rely on a previous block.  This block is called the genesis block. The genesis block is special in that its hash is not calculated using the hash of another block.

bashCoin has a function called mineGenesis() that mines a file without checking the hash of another file.  This function is called at the terminal with the command:

./bashCoin.sh minegen <file>

The function first checks to see if a genesis block exists so that it can abort before overwriting it:

[[ -f 1.blk.solved ]] && echo "A mined Genesis block already exists in this folder!" && exit 1

Next, the function will enter a loop, adding a nonce to the file and checking if its md5 hash starts with the same number of $ZEROS.  $DIFFZEROS is the difficulty variable that is calculated by bashCoin.

while [ $ZEROS != $DIFFZEROS ]
 do
 let "NONCE += 1"
 HASH=$(printf -- "`cat $1`\n\n## Nonce: #################################################################################\n$NONCE\n" | md5sum)
 HASH=$(echo $HASH | cut -d" " -f1)
 echo $HASH
 ZEROS=$(echo $HASH | cut -c1-$DIFF)
done

When the nonce is found that produces a hash that begins with the correct number of zeros bashCoin will display the results and, more importantly, build the next block in the chain.  The next block includes the hash of the genesis block.

echo "Success!"
echo "Nonce:    " $NONCE
echo "Hash:     " $HASH
printf -- "`cat $1`\n\n## Nonce: #################################################################################\n$NONCE\n" > 1.blk.solved
printf "## Previous Block Hash: ###################################################################\n" >> 2.blk
printf "$HASH\n\n" >> 2.blk

bashCoin starts the blockchain with the files “1.blk.solved” and “2.blk”.  The file that was used as the genesis is not deleted from the system but it is no longer needed for the blockchain.  When subsequent blocks are solved the “.solved” file remains but the “.blk” is deleted.

While Bitcoin rewards miners with coins, bashCoin currently does not.  Because of this, it is a good idea to include a large transaction in the genesis block before mining so that at least one participant has wealth.  bashCoin uses a specific schema for transactional data.  The following two lines can be included in the genesis file for ease of use.

tx1:user1:user1:1000000

tx2:user1:user1:1000000

When the genesis block is mined, user1 will “own” 1 million bashCoins.  user1 can then send up to 1 Mil coins to any other address.

Sending Bash Coins

After the first two transactions are included in the genesis block and it is mined, user1 can send coins to another address.  Addresses in bashCoin can be thought of as accounts that don’t need to be set up prior to receiving coins. In Bitcoin, addresses are essentially public/private key pairs.  They must be calculated before they are used. After an address in Bitcoin receives payment the private key is the only thing that allows a user to spend the balance. In bashCoin, however, any user can send transactions from any account.  There is currently no security on bashCoin addresses.

The following command allows a user to send coins in bashCoin.

./bashCoin.sh send <numOfCoins> <toAddress> <fromAddress>

The <toAddress> can be any string of letters and numbers as in “user2”.  bashCoin will go through the blockchain and calculate the balance of <fromAddress> so it must be associated with a positive balance for the transaction to work.  Use the following example to send the first transaction:

./bashCoin send 10 user2 user1

The send() function in bashCoin first assigns the arguments to variables.  (The arguments are first shifted before the send() function is called.)

SENDER=$3
RECEIVER=$2
AMOUNT=$1

After checking the current block to make sure there is a valid and live chain, send() greps the current block for the latest transaction number.  If the current block does not have transactions listed it will  look to the previous block for the latest transaction number.  If the last transaction number cannot be found then the script exits.

if [[ `cat $CURRENTBLOCK | grep "tx[0-9]*:"` ]]
 then
 #echo "block has transactions"
 # Get next tx number
 LASTTRAN=`cat $CURRENTBLOCK | tail -1 | cut -d":" -f 1 | sed 's/tx//g' | sed 's/^0*//g'`
 NEXTTRAN=`echo $LASTTRAN + 1 | bc`
 #echo Next transaction number $NEXTTRAN
 else
 #echo "block is void of transactions!"
 # Get next tx number from previous block
 LASTTRAN=`cat $PREVIOUSBLOCK | grep tx | tail -1 | cut -d":" -f 1 | sed 's/tx//g' | sed 's/^0*//g'`
 NEXTTRAN=`echo $LASTTRAN + 1 | bc`
 #echo Next transaction number $NEXTTRAN
fi
        [[ -z $LASTTRAN ]] && echo "ERROR: Couldn't find last transaction number" && exit 1

When the next transaction number is known, bashCoin will check the balance of the sending address.  checkAccountBalance() is explained below.

checkAccountBal $3

echo "Amount to send: $AMOUNT"

[[ $AMOUNT -gt $TOTAL ]] && echo "Insufficient Funds!" && exit 1

If the address has a balance greater than the sending amount, a transaction is written to the current block.

echo "Success! Sent $1 bCN to $2"
echo tx$NEXTTRAN:$SENDER:$RECEIVER:$AMOUNT >> $CURRENTBLOCK
CHANGETRAN=`echo $NEXTTRAN+1 | bc`
CHANGE=`echo $TOTAL-$AMOUNT | bc`
echo tx$CHANGETRAN:$SENDER:$SENDER:$CHANGE >> $CURRENTBLOCK

Checking Balance

bashCoin checks the balance of an address by reverse searching through the blockchain for the last time that address sent itself change.  The last change transaction in the blockchain for an address is the current balance plus any receiving transactions after it.  After bashCoin knows which block contains the users last change transaction, it can search the remaining blocks for receiving transactions.  For instance, if Alice sent Bob 100 coins and sent herself her remaining 200 coins she would end up with 200 coins.  bashCoin finds this last transaction first and then searches forward in time for any other transactions to Alice from other users.  If Bob sent Alice 10 coins after Alice sent him 100, Alice would own 210 coins.

checkAccountBal () {

ACCTNUM=$1
# Get the value of the last change transaction (the last time a user sent money back to themselves) if it exists
for i in `ls *.blk* -1r`; do
LASTCHANGEBLK=`grep -l -m 1 .*:$ACCTNUM:$ACCTNUM:.* $i`
[[ $LASTCHANGEBLK ]] && break
done

# If there was a change transaction get the value, if not print "Account has never spent money."
[[ $LASTCHANGEBLK ]] && LASTCHANGE=`grep $ACCTNUM:$ACCTNUM $LASTCHANGEBLK | tail -1` || echo "Account has never spent bashCoin."

# If account has never spent money then set LASTCHANGE to zero, if it has, separate out the tx number and value of that transaction
[[ $LASTCHANGE ]] && LASTCHANGETX=`echo $LASTCHANGE | cut -d":" -f 1 | sed 's/tx//'` && LASTCHANGE=`echo $LASTCHANGE | cut -d":" -f 4` || LASTCHANGE=0

# Get all of the receiving transactions after last change in the last change block and add them together
if [[ $LASTCHANGEBLK ]]
then
RECAFTERCHANGE=`sed "1,/tx$LASTCHANGETX/d" $LASTCHANGEBLK | grep .*:.*:$ACCTNUM:.* | cut -d":" -f4 | paste -sd+ | bc`
[[ $RECAFTERCHANGE ]] || RECAFTERCHANGE=0
#echo "Received after last change tx (same blk) = $RECAFTERCHANGE"
else
LASTCHANGEBLK=1.blk.solved
RECAFTERCHANGE=`grep .*:.*:$ACCTNUM:.* $LASTCHANGEBLK | cut -d":" -f4 | paste -sd+ | bc`
[[ $RECAFTERCHANGE ]] || RECAFTERCHANGE=0
#echo "Received after last change tx (same blk)(genesis) = $RECAFTERCHANGE"
fi


#echo $LASTCHANGEBLK
# Get all the receiving transactions after last change block and add them together
SUM=0
if [[ $LASTCHANGEBLK == 1.blk.solved ]]
then
for i in `ls -1 *.blk*`; do
[[ `grep .*:.*:$ACCTNUM:.* $i` ]] && SUM=$SUM+`grep .*:.*[^$ACCTNUM]*:$ACCTNUM:.* $i | cut -d":" -f4 | paste -sd+ | bc` || SUM=$SUM+0
done
else
for i in `ls -1 *.blk* | sed "1,/$LASTCHANGEBLK/d"`; do
[[ `grep .*:.*:$ACCTNUM:.* $i` ]] && SUM=$SUM+`grep .*:.*[^$ACCTNUM]*:$ACCTNUM:.* $i | cut -d":" -f4 | paste -sd+ | bc` || SUM=$SUM+0
done
fi


SUM=`echo $SUM | bc`
[[ $SUM ]] || SUM=0
#echo "Received after last change tx (remaining blk's)= $SUM"

# Add last change value and received money since then
TOTAL=`echo $LASTCHANGE+$RECAFTERCHANGE+$SUM`
TOTAL=`echo $LASTCHANGE+$RECAFTERCHANGE+$SUM | bc`
echo "Current Balance for $ACCTNUM:             $TOTAL"

}

Validation

The only reason we can trust transactions in this system is because we can validate every transaction from the beginning.  Every transaction ever recorded is grouped together in blocks and hashed.  Each block includes the hash of the block before it.  If a nefarious user tried to change a transaction in a previous block, the hash chain would break.  The hash of that changed block would not match the hash that was listed in the next block when it was mined.

bashCoins’s validation function is named validate().  This function first checks to see if there is more than one block in the chain.

NUMSOLVEDFILES=`ls -1 *.solved | wc -l`
(( $NUMSOLVEDFILES < 2 )) && echo "Blockchain must be greater than 1 block to validate" && exit 1

Next, it enters a loop that hashes a block, inserts the result into the next block, and hashes the result.  As long as the hashes continue to match, it will continue until the end of the chain.  If the function finds a hash mismatch it will stop and warn the user from trusting any block after the block with the bad hash.

for i in `ls -1 *.solved | tail -n +2`; do
h=`ls -1 | grep solved$ | grep -B 1 $i | head -1`
j=`ls -1 | egrep "solved$|blk$" | grep -A 1 $i | grep -v $i | tail -1`
PREVHASH=`md5sum $h | cut -d" " -f1`
CALCHASH=`sed "2c$PREVHASH" $i | md5sum | cut -d" " -f1`
REPORTEDHASH=`sed -n '2p' $j`
echo "Checking $i"
echo "Previous Hash: $PREVHASH"
#echo "Calculated Hash: $CALCHASH  Reported Hash: $REPORTEDHASH"
[[ $CALCHASH != $REPORTEDHASH ]] && echo "Hash mismatch!  $i has changed!  Do not trust any block after and including $i" && exit 1 || echo "Hashes match! $i is a good block."
done
echo "Blockchain validated.  Unbroken Chain."

Mining

Mining in bashCoin is almost the same process as mining the genesis block.  The main difference is that mine() will search for the blocks in the current directory and figure out which one needs to be mined.  Also, the validate() function is called before mine() to first verify that the blockchain is unbroken.  Mining the genesis block does not.

mine() {

while [ $ZEROS != $DIFFZEROS ]
do
# increase the nonce by one
let "NONCE += 1"
# do the hashing
HASH=$(printf "`cat $CURRENTBLOCK.wip`\n\n## Nonce: #################################################################################\n$NONCE\n" | md5sum)
HASH=$(echo $HASH | cut -d" " -f1)
# print the hash to the screen because it looks cool
echo $HASH
# cut the leading zeros off the hash
ZEROS=$(echo $HASH | cut -c1-$DIFF)
done
echo "Success!"
echo "Nonce:    " $NONCE
echo "Hash:      " $HASH
printf "`cat $CURRENTBLOCK.wip`\n\n## Nonce: #################################################################################\n$NONCE\n" > $CURRENTBLOCK.solved
rm -f $CURRENTBLOCK.wip
rm -f $CURRENTBLOCK
# Setup the next block.  Add previous hash first
printf "## Previous Block Hash: ###################################################################\n" >> $NEXTBLOCK
printf "$HASH\n\n" >> $NEXTBLOCK

}

The mine() function automatically creates the next block and includes the hash for the freshly mined block at the top of the file.

Summary

The simple concepts within Bitcoin solve several complex problems.  Namely, safeguarding wealth with strong encryption and recording an immutable, anonymous, and public ledger can be easily replicated with a bash script.  See below for the current version on bashCoin.  Copy and paste into a Linux terminal to use.

bashCoin.sh

#!/bin/bash

## Set difficulty #####################################
# Set to number of 0's that starts hash.
# 1 = Easy, 2 = Not bad, > 3 = Difficult
        DIFF=2

## Set Nonce ##########################################
# Number at which to start guessing the nonce
# No reason to change
        NONCE=0

## Other Variables ####################################
# Leave alone
        ZEROS=ff
        DIFFPLUS=1
        DIFFZEROS=0

## Functions ##########################################

getGoogleHeadline () {
        HEADLINE=$(curl -s -k "https://news.google.com/news/headlines?hl=en&ned=us&gl=US" | grep -m 1 heading | sed 's/.*aria-level\=\"2\" >//g' | sed 's/<\/a>.*//g')
}

findBlocks() {
        CURRENTBLOCK=`ls -1 *.blk | tail -1`

        # If there is no current block in the current directory then exit
        [[ -z $CURRENTBLOCK ]] && echo "No blockchain in current folder!  Try using ./bashcoin minegenesis to start a new blockchain." && exit 1

        # Get the current block's number
        CURRENTBLOCKNUM=`echo $CURRENTBLOCK | sed 's/.blk//g'`

        # If the genesis block is the only block then break out of the findBlocks function before we look for previous blocks
        if [[ $CURRENTBLOCK == "1.blk" ]]
                        then
                                                        return
        fi

        PREVIOUSBLOCKNUM=`echo $CURRENTBLOCKNUM-1 | bc`
        PREVIOUSBLOCK=`echo $PREVIOUSBLOCKNUM.blk.solved`
        NEXTBLOCKNUM=`echo $CURRENTBLOCKNUM+1 | bc`
        NEXTBLOCK=`echo $NEXTBLOCKNUM.blk`

        PREVHASH=`md5sum $PREVIOUSBLOCK | cut -d" " -f1`
}

checkSyntax () {
        # Checks to see if difficulty was setup properly
        if [ $DIFF -lt 1 ] || [ $DIFF -gt 32 ]
                        then
                                        echo "Please set difficulty to 1 through 32"
                                        exit 1
        fi
        echo "Previous Block:                                               "$PREVIOUSBLOCK
        echo "Current Block:                                "$CURRENTBLOCK
}

setup () {
        # Build the difficulty zeros based on DIFF variable
        while [ $DIFFPLUS != $DIFF ]
                        do
                                        DIFFZEROS=$(echo $DIFFZEROS"0")
                                        let "DIFFPLUS += 1"
                        done
        printf "Difficulty set to:                            $DIFFZEROS\n"
}

buildWIPBlock () {
        getGoogleHeadline
        DATE=$(date)
        printf "`cat $CURRENTBLOCK`\n\n" > $CURRENTBLOCK.wip
        printf "## Google News Headline: ##################################################################\n" >> $CURRENTBLOCK.wip
        printf "$HEADLINE\n\n" >> $CURRENTBLOCK.wip
        printf "## Mine Date and Time: ####################################################################\n" >> $CURRENTBLOCK.wip
        printf "$DATE\n\n" >> $CURRENTBLOCK.wip
}

mine () {
        # start mining, check to see if the hash starts with the winning number of zeros and if it does complete the loop
        while [ $ZEROS != $DIFFZEROS ]
        do
                        # increase the nonce by one
                        let "NONCE += 1"
                        # do the hashing
                        HASH=$(printf "`cat $CURRENTBLOCK.wip`\n\n## Nonce: #################################################################################\n$NONCE\n" | md5sum)
                        HASH=$(echo $HASH | cut -d" " -f1)
                        # print the hash to the screen because it looks cool
                        echo $HASH
                        # cut the leading zeros off the hash
                        ZEROS=$(echo $HASH | cut -c1-$DIFF)
        done

        echo "Success!"
        echo "Nonce:            " $NONCE
        echo "Hash:              " $HASH

        printf "`cat $CURRENTBLOCK.wip`\n\n## Nonce: #################################################################################\n$NONCE\n" > $CURRENTBLOCK.solved
        #printf "$HASH\n" > $CURRENTBLOCK.hash
        rm -f $CURRENTBLOCK.wip
        rm -f $CURRENTBLOCK

        # Setup the next block.  Add previous hash first
        printf "## Previous Block Hash: ###################################################################\n" >> $NEXTBLOCK
        printf "$HASH\n\n" >> $NEXTBLOCK
}

mineGenesis () {
        # first check to see if there is a blockchain already, if so exit so we don't overwrite
        [[ -f 1.blk.solved ]] && echo "A mined Genesis block already exists in this folder!" && exit 1

        # start mining, check to see if the hash starts with the winning number of zeros and if it does complete the loop
  while [ $ZEROS != $DIFFZEROS ]
  do
                                                                        # increase the nonce by one
          let "NONCE += 1"
                                                                        # do the hashing
          HASH=$(printf -- "`cat $1`\n\n## Nonce: #################################################################################\n$NONCE\n" | md5sum)
                                                                        HASH=$(echo $HASH | cut -d" " -f1)
                                                                        # print the hash to the screen because it looks cool
          echo $HASH
                                                                        # cut the leading zeros off the hash
          ZEROS=$(echo $HASH | cut -c1-$DIFF)
  done

        echo "Success!"
        echo "Nonce:    " $NONCE
        echo "Hash:     " $HASH

        printf -- "`cat $1`\n\n## Nonce: #################################################################################\n$NONCE\n" > 1.blk.solved
        #printf "$HASH\n" > 1.blk.hash

  # Setup the next block.  Add previous hash first
        printf "## Previous Block Hash: ###################################################################\n" >> 2.blk
        printf "$HASH\n\n" >> 2.blk
}

checkAccountBal () {
        ACCTNUM=$1

        # Get the value of the last change transaction (the last time a user sent money back to themselves) if it exists
        for i in `ls *.blk* -1r`; do
                        LASTCHANGEBLK=`grep -l -m 1 .*:$ACCTNUM:$ACCTNUM:.* $i`
                        [[ $LASTCHANGEBLK ]] && break
        done

        # If there was a change transaction get the value, if not print "Account has never spent money."
        [[ $LASTCHANGEBLK ]] && LASTCHANGE=`grep $ACCTNUM:$ACCTNUM $LASTCHANGEBLK | tail -1` || echo "Account has never spent BashCoin."

        # If account has never spent money then set LASTCHANGE to zero, if it has, separate out the tx number and value of that transaction
        [[ $LASTCHANGE ]] && LASTCHANGETX=`echo $LASTCHANGE | cut -d":" -f 1 | sed 's/tx//'` && LASTCHANGE=`echo $LASTCHANGE | cut -d":" -f 4` || LASTCHANGE=0

        # Print the value of the last change transaction (the value of the users account before any other received transactions)
        #echo Last Change = $LASTCHANGE
        #echo Last Change Transaction Number = $LASTCHANGETX

        # Get all of the receiving transactions after last change in the last change block and add them together
        if [[ $LASTCHANGEBLK ]]
                        then
                                        RECAFTERCHANGE=`sed "1,/tx$LASTCHANGETX/d" $LASTCHANGEBLK | grep .*:.*:$ACCTNUM:.* | cut -d":" -f4 | paste -sd+ | bc`
                                        [[ $RECAFTERCHANGE ]] || RECAFTERCHANGE=0
                                        #echo "Received after last change tx (same blk) = $RECAFTERCHANGE"
                        else
                                        LASTCHANGEBLK=1.blk.solved
                                        RECAFTERCHANGE=`grep .*:.*:$ACCTNUM:.* $LASTCHANGEBLK | cut -d":" -f4 | paste -sd+ | bc`
            [[ $RECAFTERCHANGE ]] || RECAFTERCHANGE=0
            #echo "Received after last change tx (same blk)(genesis) = $RECAFTERCHANGE"
        fi
        #echo $LASTCHANGEBLK
        # Get all the receiving transactions after last change block and add them together
        SUM=0
        if [[ $LASTCHANGEBLK == 1.blk.solved ]]
                        then
      for i in `ls -1 *.blk*`; do
        [[ `grep .*:.*:$ACCTNUM:.* $i` ]] && SUM=$SUM+`grep .*:.*[^$ACCTNUM]*:$ACCTNUM:.* $i | cut -d":" -f4 | paste -sd+ | bc` || SUM=$SUM+0
      done
                        else
                                        for i in `ls -1 *.blk* | sed "1,/$LASTCHANGEBLK/d"`; do
        [[ `grep .*:.*:$ACCTNUM:.* $i` ]] && SUM=$SUM+`grep .*:.*[^$ACCTNUM]*:$ACCTNUM:.* $i | cut -d":" -f4 | paste -sd+ | bc` || SUM=$SUM+0
      done
        fi
        SUM=`echo $SUM | bc`
        [[ $SUM ]] || SUM=0
        #echo "Received after last change tx (remaining blk's)= $SUM"

        # Add last change value and received money since then
        TOTAL=`echo $LASTCHANGE+$RECAFTERCHANGE+$SUM`
        TOTAL=`echo $LASTCHANGE+$RECAFTERCHANGE+$SUM | bc`
        echo "Current Balance for $ACCTNUM:     $TOTAL"
}

send() {

        SENDER=$3
        RECEIVER=$2
        AMOUNT=$1

        # Check if current block is solved just to make sure the blockchain is still live
        CURRENTBLOCKCHECK=`ls -1 *.blk | tail -1 | grep solved`
        if [[ $CURRENTBLOCKCHECK ]]
                        then
                                        echo "The current block is already solved!"
                                        echo "ERROR: need unsolved block"
                                        exit 1
        fi

        # Check to see if current block has transactions listed
        if [[ `cat $CURRENTBLOCK | grep "tx[0-9]*:"` ]]
                        then
                                        #echo "block has transactions"
                                        # Get next tx number
                                        LASTTRAN=`cat $CURRENTBLOCK | tail -1 | cut -d":" -f 1 | sed 's/tx//g' | sed 's/^0*//g'`
                                        NEXTTRAN=`echo $LASTTRAN + 1 | bc`
                                        #echo Next transaction number $NEXTTRAN
                        else
                                        #echo "block is void of transactions!"
                                        # Get next tx number from previous block
                                        LASTTRAN=`cat $PREVIOUSBLOCK | grep tx | tail -1 | cut -d":" -f 1 | sed 's/tx//g' | sed 's/^0*//g'`
                                        NEXTTRAN=`echo $LASTTRAN + 1 | bc`
                                        #echo Next transaction number $NEXTTRAN
        fi

        [[ -z $LASTTRAN ]] && echo "ERROR: Couldn't find last tranasction number" && exit 1

        checkAccountBal $3

        echo "Amount to send: $AMOUNT"
        #echo Your current account balanace: $TOTAL

        [[ $AMOUNT -gt $TOTAL ]] && echo "Insufficient Funds!" && exit 1

        echo "Success! Sent $1 bCN to $2"
        echo tx$NEXTTRAN:$SENDER:$RECEIVER:$AMOUNT >> $CURRENTBLOCK
        CHANGETRAN=`echo $NEXTTRAN+1 | bc`
        CHANGE=`echo $TOTAL-$AMOUNT | bc`
        echo tx$CHANGETRAN:$SENDER:$SENDER:$CHANGE >> $CURRENTBLOCK
}

validate() {
        # Check that there are blocks to validate
        NUMSOLVEDFILES=`ls -1 *.solved | wc -l`
        (( $NUMSOLVEDFILES < 2 )) && echo "Blockchain must be greater than 1 block to validate" && exit 1

        for i in `ls -1 *.solved | tail -n +2`; do
                        h=`ls -1 | grep solved$ | grep -B 1 $i | head -1`
                        j=`ls -1 | egrep "solved$|blk$" | grep -A 1 $i | grep -v $i | tail -1`
                        PREVHASH=`md5sum $h | cut -d" " -f1`
                        CALCHASH=`sed "2c$PREVHASH" $i | md5sum | cut -d" " -f1`
                        REPORTEDHASH=`sed -n '2p' $j`
                        echo "Checking $i"
                        echo "Previous Hash: $PREVHASH"
                        #echo "Calculated Hash: $CALCHASH  Reported Hash: $REPORTEDHASH"
                        [[ $CALCHASH != $REPORTEDHASH ]] && echo "Hash mismatch!  $i has changed!  Do not trust any block after and including $i" && exit 1 || echo "Hashes match! $i is a good block."
        done
        echo "Blockchain validated.  Unbroken Chain."
}

case "$1" in
        mine)
                        validate
                        findBlocks
                        checkSyntax
                        setup
                        buildWIPBlock
                        mine
                        exit 0
                        ;;
        minegenesis|minegen)
                        shift
                        [[ -z $@ ]] && echo "Usage: ./bashCoin minegenesis <filename>" && echo "This command mines the first block (any file you like)." && exit 1
                        setup
                        mineGenesis $1
                        ;;
        send)
                        shift
                        [[ -z $@ ]] && echo "Usage: ./bashCoin send <amount> <toAddress> <fromAddress>" && exit 1
                        findBlocks
                        send $@
                        exit 0
                        ;;
        checkbalance|checkbal|bal)
                        shift
                        [[

 -z $@ ]] && echo "Usage: ./bashCoin bal <address>" && exit 1
                        checkAccountBal $1
                        exit 0
                        ;;
        findblocks)
                        findBlocks
                        ;;
        validateblockchain|validate|val)
                        validate
                        exit 0
                        ;;
        *)
                        echo $"Usage: $0 {mine|send|checkbalance(bal)|minegenesis(minegen)}"
                        exit 1
                        ;;
esac

exit 0
Learning How to Use Bitcoin: A Beginner’s Guide to Using the Bitcoin Testnet

Learning How to Use Bitcoin: A Beginner’s Guide to Using the Bitcoin Testnet

a beginner's guide to using the bitcoin testnet

Intro

Beginners to Bitcoin may find the concepts and the scope of the network overwhelming. The idea of trading real currency for digital currency can sound scary, especially when the beginner is not familiar with how blockchain works or even how to send and receive coins. An ideal situation for learning how to use Bitcoin would not involve trading real money in the process. In this post, I’d like to cover the Bitcoin Testnet: a zero-risk testing network that allows the beginner to trading Bitcoins as if they were on the main network.

The Bitcoin network is divided, so to speak, into three networks:

  • The main network (where coins are traded as real currency),
  • A test network called the Testnet (where coins with no associated value are traded for testing purposes), and
  • A regression testing network (where coins are created instantly and are never traded to others outside the user’s network).

Coins mined in one network stay in that network, thus coins cannot be transferred between networks.  It is because of this separation that we are able to use the Testnet as an environment for learning.

Testnet Coins

Both the main Bitcoin network and the Testnet network contain live blockchains and real users trading real, mined coins.  Bitcoins on the main network have real value associated with them whereas the Testnet bitcoins do not.

The main difference (as far as the beginner are concerned) between the coins on both networks is whether or not everyone agrees they have value.  Testnet coins are given away for free to anyone that wants them. Coins on the main network are traded for goods and services in the same way United States currency is.

Coins for the Testnet are given out for free from what are called “Faucet Websites.” These websites are set up by miners or other users with a surplus of Testnet coins.  They send coins to anyone who requests them and kindly asks for their return when the user is finished with them.

Trading coins on the Testnet is exactly the same process as trading them on the main network. The process goes like this: Blocks are mined, coins are generated by the mining, users are sent Bitcoins by other users, the transaction is recorded in the blockchain, blocks of transactions are mined, and the process repeats. Testnet coins are used to generate transactions in the Testnet blockchain and are used both by beginners and developers who are testing new Bitcoin-based programs.

The Bitcoin Testnet implementation does not require a separate installation. Bitcoin wallets that have the ability to connect to the Testnet can be started with a special flag that will direct the software to connect to the Testnet blockchain instead of the main network blockchain.

As with the main network, though, the software will need to download the current blockchain to properly synchronize.  Luckily, however, the size of the Testnet blockchain is far less than the main blockchain.  As of February 2018 the size of the main blockchain is about 156 Gigabytes whereas the size of the Testnet blockchain is only about 14 Gigabytes.

How to Set Up Bitcoin Core for Testnet

A Bitcoin Core instance can be started with the ‘-testnet’ flag to connect to the Testnet blockchain instead of the main blockchain.

From an Ubuntu machine: download Bitcoin Core and start with the following commands (check bitcoin.org for the latest version):

cd ~/Documents
 wget https://bitcoin.org/bin/bitcoin-core-0.15.1/bitcoin-0.15.1-x86_64-linux-gnu.tar.gz
tar xfz bitcoin-0.15.1-x86_64-linux-gnu.tar.gz
cd bitcoin-0.15.1/bin
./bitcoin-qt -testnet

The bitcoin-qt binary is the GUI version of Bitcoin Core.  The last command will open a new window and start syncing with the Testnet blockchain.

Electrum: What is it, Pros & Cons

Unlike Bitcoin Core, Electrum does not need to download and sync to the entire blockchain.  The upside to this is it only takes a few minutes to get up and running.  The downside is you cannot explicitly trust the blockchain.  Although not trusting the blockchain is acceptable in a zero-risk learning environment, the rest of this blog will refer to Bitcoin Core.

Start Electrum with the ‘–testnet’ command to connect to the Testnet blockchain.  Below are commands that will install and start Electrum on Ubuntu.

sudo apt-get install python3-setuptools python3-pyqt5 python3-pip

sudo pip3 install https://download.electrum.org/3.0.5/Electrum-3.0.5.tar.gz

electrum --testnet

How Bitcoin Trading Works

After the blockchain has been synchronized you can begin trading Bitcoins (BTC).

On the main Bitcoin network, coins can be obtained from either mining, receiving them from another user, or buying them from a BTC exchange.

On the Testnet network, coins can be requested from Faucet websites such as https://testnet.manu.backend.hamburg/faucet.

Faucets require an address to which they send coins.  To obtain a receiving address, click on the ‘Receive’ button from the top of the Bitcoin Core screen followed by the ‘Request Payment’ button as seen below.

receive button

The Faucet will then send a certain amount of coin (usually around 1 BTC) to the address you provided.  When you receive BTC from the Faucet you will see a notification popup and a positive balance on the main Bitcoin Core screen.  You will also be able to see the transaction date, time, amount, and ID from the ‘Transactions’ screen.

bitcoin core screen transactions

BTC received will not be available to spend until the transaction has been confirmed in the Blockchain. Depending on the software and the level of trust it has of the blockchain, the funds will be available after one or many successfully mined blocks.  From the ‘Overview’ menu you will see ‘Available’ and ‘Pending’ balances. BTC in a pending status is not available to spend.

available and pending balances from the overview menu

Sending Bitcoins is the same process but in reverse.  A user will provide you with a receiving address when they are expecting to be paid.  In Bitcoin Core (or any other Bitcoin Wallet) you type or scan this address into the ‘Pay To’ field.

Receiving addresses are essentially the public key in a Public/Private key pair.  The receiver allows you to encrypt the Bitcoins you are sending with their public key.  After encryption, the only way to access the coins, and thus spend them, is to decrypt them with the private key.

Since a public key in a Public/Private key pair is, theoretically, open to cracking, and since the Bitcoin implementation is focused on anonymity, Public/Private key pairs are rotated regularly.  It is common for a user to provide a new public key each time they expect payment.  This behavior is not mandatory, however.  Users that request donations and organizations that don’t require anonymity can give out the same public key for multiple transactions.

Since a user is encouraged to give out many public keys for their transactions they are left with many private keys that access the coins.  These private keys are stored in what is called the wallet.

The Wallet

The value inside your wallet (your wealth) is locked away inside a complex mathematical formula using your public key.  The only key to this lock is essentially the answer to that formula: the private key.  Anyone with access to the private key owns the right to spend the Bitcoins associated with it.

By default, the file that contains the private key is not encrypted.  This leaves the private key open to attack and theft.  Keeping your private key(s) encrypted is a security imperative.  Before you receive or spend Bitcoin, encrypt your wallet in Bitcoin Core by clicking on ‘Settings’ and then ‘Encrypt Wallet…’.

bitcoin core encrypt wallet

Similarly, if you lose your wallet, you lose your private key(s).  The wallet, when used with Bitcoin Core, is stored in your home directory under a hidden folder called ‘.bitcoin’ as a file name ‘wallet.dat’.  This file should remain protected with encryption and regularly backed up.

Viewing Transactions

Once the transaction has been mined inside a block in the blockchain it will be available to view from a website that tracks the Blockchain.  From the ‘Transaction’ screen in Bitcoin Core, you will find the transaction ID.  This ID can be copied and pasted into a website such as https://testnet.blockexplorer.com/.  See below for an example.

testnet transaction ID

Notice that all information about the transaction is publically available except for the private keys.  This information is available for every transaction that has ever occurred in the blockchain to anyone who wants it.  Also notice, however, that we did not associate our accounts with names, email address, etc.  No identifying information is ever needed to take part in a Bitcoin transaction.  The only thing tying a user to their Bitcoins is the private key associated with the public key to which Bitcoins were sent.

Summary

Learning how to use Bitcoin using the Testnet is quick and simple.  It is possible, in just a few steps, to learn how to install and encrypt a wallet, receive coins, spend coins, and track transactions all without spending real money.

All of the steps described above also apply to Bitcoin Core when it connects to the main blockchain.

Once you are done testing and learning, you can restart Bitcoin Core without the ‘-testnet’ flag to get started with real Bitcoin transactions and track them by removing ‘testnet.’ from the blockexplorer.com link.  Also, make sure to send borrowed Testnet coins back to the faucet website from which they came.