Right-Click save target as to download PDF - the www.Proj354.com

celerymoldwarpSecurity

Dec 3, 2013 (3 years and 8 months ago)

281 views

Fi nal Report
Christina Jewell
William Chan
Curtis St-Onge
Torque: Digital Excavation

Tabl e of Contents
Executive Summary
3
Project Vision
5
Project Team
7
Achievements
9
Overcoming Obstacles
11
Efficiency
14
Recommendations
16
Conclusion
18
Glossary
20
References
23
Appendix A: Project Budget
25
Appendix B: Gantt Chart
28
Appendix C: Change Notices
35
Appendix D: Hardware Specifications
40
Appendix E: Networking Diagram
42
Appendix D: Source Code
44
Appendix E: Administrator Manual
77
Torque Final Report
1
Torque Final Report
2
Executi ve Summary
Torque Final Report
3
Executive Summary
With the rise in popularity of the digital currency, Bitcoin (BTC), the group Torque decided to undergo the Digital
Excavation project in hopes of gaining some Bitcoins. Bitcoins are received as a reward for solving complex
mathematical problems using the processing power of computers. The first to solve the cryptographic hash wins the
Bitcoin prize, and this process is repeated every 10 minutes on average. At the writing of this report, a single Bitcoin is
valued at $143USD [1] and the reward for solving one block is 25BTC, a combined total of $3575! The value of Bitcoin
has been on a steady increase since its introduction [2], which makes this project quite valuable.
In order to increase our chances of solving the hash first, Torque produced a virtualized cluster of 28 systems using
VMware Vsphere. Each Virtual Machine ran on one core of a physical machine CPU, and ran a mining program that
connected them all to the Bitcoin Server we set up.
Due to limited resources and the need for a VPN service, the cluster of systems was not able to effectively begin mining
until the end of March.
The project power consumption was monitored and calculated against the profit that would be gained from solving a
block and was found to be ineffective. The odds of solving a block using only CPU power, no matter how many you
connect, are extremely low, and the power costs to run so many machines is quite high.
Torque used a combination of Active Directory, Domain Name Server, Network File System, and Remote Desktop to
effectively manage and monitor our systems remotely. Torque used a Virtual Private Network to tunnel out of the network
and access the Bitcoin port. ESXi, VMware VCentre and VSphere were used to setup our systems.
The entire collection of systems was connected to one of two Uninterruptible Power Supplies (UPS) to ensure that in the
case of a power failure or power surge, our system would not be damaged. The hard drives used to store our data were
setup using RAID 10 and RAID 50 to prevent the loss of any data should one of the disks fail.
Our final deliverable was an almost completely virtualized implementation of our proposed network, capable of mining
Bitcoins at an average rate of 29MH/s, running 24 hours a day, 7 days a week.
Torque Final Report
4
Proj ect Vi si on
Torque Final Report
5
Project Vision
In 2009, Satoshi Nakamoto released Bitcoin (BTC) into the world [3]. Since then, a register or ledger of all Bitcoin
transactions on the network has been kept. This record is called the blockchain. Each time a block is added to the
blockchain through a process called mining, 25BTC are added to the world, given to the miner who solved the block.
Bitcoin itself is a currency used by the Bitcoin software, transferred over the Bitcoin network using the Bitcoin protocol.
How Bitcoins are mined is defined in both the protocol and software implementations, basically, mining used
cryptography to confirm that each transaction is legitimate, essentially, that the Bitcoins included in the transaction exist,
and have not yet been spent elsewhere and are being sent to legitimate Bitcoin addresses on the network. This is done
using hash values of previous transactions and computing many mathematical functions to prove the transaction true.
Groups of confirmed transactions are grouped together into an object called a block. These blocks are then verified using
the same cryptographic function by other miners on the network. Another way of looking at this process is that it is a
brute force method of finding the next valid block. A block is valid if the block header matches the expected header at
the current level of difficulty. The valid blocks are broadcasted and confirmed by the network, and it is added to the
blockchain and a reward of 25BTC is given to the miner who solved that block by including that miners Bitcoin address
in the new block. This happens approximately every 10 minutes, making it a race to see who gets it first.
The Bitcoin network is operated using Peer-to-Peer technology. Every machine running the Bitcoin software on the
network is considered to be a node. Nodes communicate with each other using P2P to communicate new transactions
to each other, and then to confirm those transactions by mining. All nodes have a full copy of the blockchain stored
locally, and those nodes who are using mining software provide the security of those transactions by computing
mathematical functions to confirm that those transactions are not false.
The entire network has no central issuing authority, but instead relies on the cooperation of all other nodes on the
network. This way, both the currency and the payment methods remain free from the risks of inflation, free from the
control of government (so far), and also because transactions must be confirmed by multiple nodes, the network is
considered to be quite secure.
As was mentioned earlier, the number of Bitcoins in circulation increases at a steady rate, a new coin approximately every
10 minutes, based on the Bitcoin protocol. Difficulty is adjusted to maintain this ratio. The slight change in the rate of
bitcoin generation is due to the reward drop which occurred on November 28th [4]. Because of the proven consistency
of bitcoin generation, this project seems to be worth undertaking.
Torque Final Report
6
Proj ect Team
Torque Final Report
7
Christina Jewell
Christina is our main software expert.This is because of her skill and experience with different programming languages
and methods. Christina is an asset to the team because of her ability to effectively troubleshoot and diagnose software,
regardless of its origin. She will provide this project with efficient and secure software applications. As well, Christina will
be the driving force behind the design aspects of the project.
William Chan
William is our main networking expert due to his vast knowledge with networking equipment, connectivity and system
administration tasks. We are confident that we will have a fully functional network system with all of the required services
available to us. As well, being a system administrator will allow him to providing support when needed throughout the
duration of the project.
Curtis St-Onge
We have selected Curtis as our resident hardware expert. He is known for his great knowledge and background in
troubleshooting problems and the in-depth understanding of computer hardware. In order to achieve our final goal, his
expertise will be required to gain access to the computer systems and servers to perform our duties.
Torque Final Report
8
Achi evements
Torque Final Report
9
Achievements
Our Capstone project was required to fulfill, at minimum, the following categories: Software, Hardware, Networking,
Security and 3 Server Services. Torque not only fulfilled these categories in full, but also incorporated fault tolerance into
our project by connecting every machine to one of two UPS to prevent abrupt power failure and using RAID 10 or RAID
50 on our Hard Drives to give extra redundancy and maximize storage space. We also have a backup server connected
to the Bitcoin network, ready to drop in should something happen to our current server.
Our Server Services were fulfilled by using Active Directory to build up our infrastructure. We added the Domain
Controller, then a Member Server which functioned as a Remote Desktop Session Host and Domain Name Server and a
CentOS server for NFS. We had a routing Server and a VCentre server as well.
The security aspects of our project were encrypting the Bitcoin wallet, setting up a firewall, and using a VPN service. We
also set up appropriate User Account Controls, and Group Policy settings on our Active Directory. In addition to this, we
used CentOS to configure a VM Heartbeat monitor so we could be notified should something happen to one of our
miners.
The software used in this project included several Operating Systems (Windows Server 2008 R2, CentOS, Xubuntu) and
several VMware applications (VCentre, VSphere). We researched many differeny Bitcoin Servers and Miners, checking
the source code and thoroughly testing the functionality before we decided on using the original Bitcoin client, bitcoind,
for the server and Ufasoft Coin as the miner.
For networking requirements, we implemented two separate networks. One was an internal management network
connected to Switch 1, which hosted Active Directory, the Member Server including VCentre and RDP, the NFS Server,
and the Datastore Heartbeating. This kept the network isolated and provided an extra layer of security. Our second
network, connected to Switch 2, connected to a home router that was forwarded to the VPN server, and provided a
DHCP service to all of our machines that required it.
Finally, our hardware requirements were most definitely met. By the end of our project, we had 3 servers and 13
machines all up and running in a clustered system. The difficult part was keeping them all running using the UPS and two
separate circuits to prevent tripping a breaker.
Overall we are very pleased with how our project turned out, having learned a tremendous amount throughout the course
of the Capstone project, and finding many different ways to put our theoretical knowledge to use in real world
applications.
Torque Final Report
10
Overcomi ng Obstacl es
Torque Final Report
11
Summary
There were 3 major obstacles during the course of our capstone project; The need for a VPN server, The Bitcoin reward
drop, and The blockchain fork. All 3 of these obstacles were overcome, and we all learned some things in the process.
Bitcoin Reward Drop & Difficulty Increase, November 28, 2012
For every 210, 000 blocks added to the blockchain the reward gained for mining a single block gets cut in half. On
November 28th, 2012, a group of miners known as Slush’s Pool mined the block [5] that caused the reward drop,
containing 457 transactions. The reward went from 50BTC down to 25BTC for a single block. In addition to this, the
difficulty level for mining one block increased. This was part of the original Bitcoin Protocol [7], and will continue to occur
until 21 million Bitcoins are in circulation [6].
This event posed an unfortunate scope change for the project, since it became less likely that we would be able to mine
a block, and the reward for doing so was significantly less. However, we pushed through the disappointment and much
to our surprise, the value of a single Bitcoin went from around $10 before the drop, to over $140 by the end of our
project. So despite the reward drop, the market for Bitcoin has grown stronger and the potential reward for one block is
over $3575, where before it was only around $500.
Blockchain Fork, March 12, 2013
Early in the morning on March 12, 2013, the Bitcoin network ran into a major problem. The Bitcoin Blockchain forked,
creating two separate chains of transactions [8]. One chain being added to by miners running version 0.7 and the other
being added to by those running version 0.8.
The reason for this fork was the database for the 0.8 version of the software implemented a new database, able to
handle larger block sizes than the previous 0.7 version. So when Slush’s pool mined block #225430, containing 1752
transactions [9], those nodes running 0.8 accepted the block and kept building on top of that one, but those nodes
running 0.7 rejected it, accepting several smaller blocks containing those same transactions, and continued building on
their chain.
Approximately every 10 minutes, a new block is added to the chain, and so a solution needed to be put into place swiftly
to avoid disaster. The only immediate solution was to get miners to revert to 0.7 since it is the only version of the Bitcoin
daemon that is backwards compatible. During the 24 hours surrounding the fork, the price for 1BTC dropped 23%. This
soon recovered though. Once the 0.7 version of the blockchain became longer than the 0.8 version, the 0.8 version was
orphaned. The orphaned chain is still included in the blockchain, but all future blocks are added to the main chain.
A patch was installed in the 0.8 version miner and is now available for download or upgrade from the bitcoin.org website.
Miners can still run the 0.7 version for now, but on May 1, 2013, they are forcing all users to upgrade and use the 0.8.1 in
order to keep Bitcoin moving forward.
Torque Final Report
12
VPN Required
One of the obstacles we faced was gaining access to the Bitcoin port 8332 through the current network firewall. Since
we were using our providers network we had restricted access to the internet. This prevented our server from being able
to reach the Bitcoin network to sync the block chain and verify the miners hash work.
After planning, and discussing the multiple methods with our sponsor, we gained approval for use of a VPN Service to
access the external network without any restrictions. The simplest and by far cheapest method was for us to get a Home
Router compatible with DD-WRT to setup as the PPTP gateway for the unrestricted access on an Telus ADSL
Connection. This method allowed for us to have access to the Bitcoin port and provided a Stateful Packet Inspector
firewall to be one of the first barriers in protecting our Bitcoin server and Miners.
After setting the up the Service we were trying to connect the to the PPTP Service through Linux, but we were unable to
connect to the PPTP service unless we were in MD025. This was strange because we were able to connect using
Windows PC’s from anywhere in the school. I suspect that it is either an encryption issue or possibility an authentication
error, but we did not have the time to investigate it further. So we had to devise a work around, which was to use a
Windows 2008 R2 server as a VPN dialer which will connect to our VPN Server, then it will forward the connection to a
secondary NIC card which is attached to a Home router. This will allow any systems and devices attached to the home
router directly or indirectly to have unrestricted network access.
Torque Final Report
13
Effi ci ency
Torque Final Report
14
Mining Efficiency
Our Bitcoin Server is running on one of the Core 2 Duo machines, and each miner connects to it using a remote
procedure call(RPC). We have a backup server running on a Core 2 Quad machine, with no RPC connections. For
comparison, we left one miner running on a Core 2 Duo physical machine to compare the efficiency against a virtualized
miner running on the same architecture. For virtualized miners, we have 10 miners running on the 2 Core i7 nodes, we
have 4 miners running on 1 Core 2 Quad node, we have 14 miners running on 7 Core 2 Duo nodes.
Node #
CPU Core
Speed
# of miners
Hash Rate MH/s
Efficiency
0
Core i7
3.4GHz
5
5.18
5 Threads, each running 1.04MH/s
1
Core i7
3.4GHz
5
4.92
5 Threads, each running 0.98MH/s
2
Core 2 Quad
2.5GHz
4
3.56
4 Threads, each running 0.89MH/s
4
Core 2 Duo
3GHz
2
2.14
2 Threads, each running 1.07MH/s
5
Core 2 Duo
3GHz
2
2.14
2 Threads, each running 1.07MH/s
7
Core 2 Duo
3GHz
2
2.14
2 Threads, each running 1.07MH/s
3
Core 2 Duo
2.33GHz
2
1.68
2 Threads, each running 0.84MH/s
6
Core 2 Duo
2.33GHz
2
1.67
2 Threads, each running 0.84MH/s
8
Core 2 Duo
2.33GHz
2
1.67
2 Threads, each running 0.84MH/s
9
Core 2 Duo
2.33GHz
2
1.68
2 Threads, each running 0.84MH/s
The Core 2 Duo running at 3GHz is the most efficient miner, followed by the Core i7 miners, then the Core 2 Quad
miners, and the most inefficient miners are the Core 2 Duo miners running at 2.33GHz.
CPU Core
Combined Hash Rate
Hardware Cost
Mining Cost
Core i7 @ 3.4GHz
10.1 MH/s
$2150
$212.87 / MH
Core 2 Quad @ 2.5GHz
3.56 MH/s
$600
$168.54 / MH
Core 2 Duo @ 3GHz
6.42 MH/s
$717
$111.68 / MH
Core 2 Duo @ 2.33GHz
6.7 MH/s
$956
$142.69 / MH
The most cost effective miner, given the hardware prices is the Core 2 Duo with a speed of 3GHz, followed by the Core 2
Duo with a speed of 2.33GHz, then the Core 2 Quad and lastly the Core i7. These calculations are based solely on the
cost of the hardware and the combined speed of the miners running on them. This does not include the power costs
associated with each machine. Given, that for a price of $212.87 per MH/s you are only running 2 machines, compared
to a price of $142.69 per MH/s you are running 4 machines and potentially doubling your electricity costs.
Overall there is not a significant difference in the hash rate from one CPU to the next, they all run approximately 1MH/s on
each core, and our physical miner has very much the same rate, running at a rate of 2.15 MH/s on 2 cores.
Torque Final Report
15
Recommendati ons
Torque Final Report
16
Recommendations
With the increased difficulty, (7,673,000 as of April 7 2013) [10] and the recent reward drop, (25BTC/block) it is not
advisable to attempt solo mining without investing in specially built hardware, such as the ASIC Bitcoin Miner from
Butterfly Labs that will allow speeds of up to 50 Giga Hashes per Second (GH/s) [12]. Our project attempted to setup a
Bitcoin mining cluster, using only CPU power from 9 different workstations, running one VM on each core of the
processor, each one running at around only 1 MH/s, with a combined total of 29MH/s. Given our power
consumption(19Amps), we definitely were not being profitable.
Using the Bitcoinx profit calculator [11], and inputing our system values, it was estimated that it would take over 36 years
to generate a single block. Though Bitcoin mining can be compared to winning the lottery, given the immense computing
power that pooled miners have, it is extremely unlucky that we would mine a block sooner than the estimated time, if at
all. Thus, we are really just paying for electricity.
Because the efficiency of the mining program that we are using is more efficient then some of the other programs that we
originally tested, it is not recommend to use CPU mining. From an administrative standpoint it makes sense to have a
consolidated cluster for management purposes. Running a cluster to mine does not increase hash rate since the hash
rate is in direct relation to the speed and type of processor and amount of cores on the CPU.
Other alternatives could have been to join a pool, used GPU cards, made an initial investment in specific mining
hardware. Joining a pool would have produced a much smaller but more consistent payout. But still, the profit gained
would not have offset the cost of electricity, since payouts from joining a pool are based on how much MH/s you
contribute, and our 50MH/s is still small in comparison to the combined hash rate of any pool [13]. Using GPU cards
would have greatly increased our chances of solo mining a single block, or increased our payout from pooled mining.
And if the budget had allowed it, investing in mining hardware would have definitely given us a fighting change in the race
to solve the next block and receive the full payout.
Torque Final Report
17
Concl usi on
Torque Final Report
18
Conclusion
Bitcoin mining is an conceptually interesting project, and is fun to undertake in your free time. The Bitcoin community is
also quite friendly and helpful, and definitely on the rise in popularity.
Since beginning our project in September of 2012, the combined hash rate of the Bitcoin network went from 20,000GH/
s to over 55,000GH/s [14]. Which greatly overshadows our tiny 50MH/s
By the end of the project we anticipated having a clear understanding of what would be needed to effectively make a
profit mining Bitcoins. Through trial and error, experimenting with different software and hardware, and monitoring our
power consumption we now know that CPU mining is extremely ineffective at this point in the lifecycle of Bitcoin. Our
entire cluster of 29 miners has a combined rate of 29MH/s, less than that of a single modern GPU card, and contributing
to less than .00000009% of the combined network hashing power.
With 1000s of merchants already accepting bitcoins worldwide, bitcoins are increasing in popularity and in price/value. In
hindsight, it would have been much more profitable to buy bitcoins, let the market rise and then sell them. But that kind
of investment has nothing to do with IT infrastructure behind the bitcoin protocol.
Torque Final Report
19
Gl ossary
Torque Final Report
20
Bitcoin Related Terms
Address :
The address of your Bitcoin account.
Wallet :
Holds addresses and shows the balance of those accounts.
Bitcoin :
A P2P and open source digital currency.
Blockchain :
Chronological public record of all of the transactions on the Bitcoin network.
Block :
A group of transactions, that gets added to the blockchain approximately every 10 minutes.
Transaction :
The exchange of any amount of Bitcoins between two addresses.
Hash Rate :
Measuring unit for the amount of processing power on the network.
P2P :
Peer to Peer, individuals interact without the use of a third party
Digital Currency :
Bitcoin is a digital currency, though there can be physical coins associated with it.
Bitcoin Mining :
Using computer processing power to do mathematical calculations on the network, confirming
transactions that occur.
Bitcoin-QT :
The bitcoind cleint with a GUI interface.
Bitcoind
:
The original bitcoin client, A bitcoin server and wallet command line based.
Miner :
Computer hardware doing complex mathematical calculations in hopes of generating bitcoin.
Hash Rate :
Measuring unit of the processing power of the bitcoin network.
RPC :
Remote Procedure Call - Used by miner and server to contact each other.
IT Related Terms
Clustering :
Software used to group Bitcoin clients together in an effort to generate more bit coin.
Linux :
A open source Operating system.
Kernel :
An interface between the hardware and applications(i.e. user)
Distribution :
The Version of Linux.
Operating System :
A collection of hardware and software resources that’s provides common services and
functions for programs/applications.
CPU :
Central Processing Unit: is the hardware that performs all of the basic arithmetical, logical and input output
operations in a computer system.
CPU Time :
The amount of time for which the CPU is working for example waiting for Input/output.
RAM :
Random Access Memory
Switch :
A device allows connectivity and communications between computer systems.
DHCP :
Dynamic Host Configuration Protocol - Dynamically assigns network addresses
DNS :
Domain Name System - Maps IP addresses to hostnames.
Hardened Down Server :
Bare bone server that is stripped down to be the most secure possible.
Software :
Instructions for the hardware Usually GUI based.
Routers :
A networking device that accepts and forwards data packets on a network.
UPS :
Uninterruptible Power Supply: Used in situation where improper shutdown is not tolerated.
Tar :
Tape Archive = Used to bundle/archive files and folders.
Make :
Makes files needed - configures and installs programs
Sudo :
Super User Do allows you to run programs with root privileges
Torque Final Report
21
cd :
Change Directory
ls :
Lists files and folders
Firewall :
controls outgoing and incoming network traffic.
NFS :
Network File System
Exports :
Use this to configure NFS settings.
Active Directory :
A computer phonebook
RDP :
Remote Desktop Protocol
VMware tools :
Used to manage vm's and transfer files between Host system.
DC :
Domain Controller
DCPromo :
Used to promote a member server to a domain controller
Domain :
Collection of computers, users, and policies.
Group Policies :
Administrative Policies placed on users and groups to restrict or customize a users experience.
OU :
Organizational Unit : Used to group active directory objects.
Member Server :
Is a server that is connected to the domain that doesn't control Active directory but controls other
things like File servers, Web servers, RDP servers and database servers.
CAL :
Client Access License
Remote Desktop :
Allows you to connect to computers remotely
DD-WRT :
Custom firmware based on a lightweight Linux.
Firmware :
A program with a small amount of data held in non-volatile memory.
PPTP :
Point to Point Protocol - Used for basic VPN connections encapsulates all packets to PPP packets.
Telnet :
A program that connects your PC to another device on the network.
TFTP :
Trivial File Transfer Protocol
Torque Final Report
22
References
Torque Final Report
23
References
[1] Internet:
http://bitcoincharts.com/charts/mtgoxUSD#rg60ztgSzm1g10zm2g25zv
[April 6 2013]
[2] Internet:
http://blockchain.info/charts/total-bitcoins
[April 7, 2013]
[3] Internet:
https://en.bitcoin.it/wiki/History
[April 7, 2013]
[4] Internet:
http://bitclockers.com/miningcalculator
[April 7, 2013]
[5] Internet:
http://blockchain.info/block-index/
322335/000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e
[April 7, 2013]
[6] Internet:
http://bitcoinclock.com
/ [April 7, 2013]
[7] Internet:
http://bitcoinmagazine.com/block-reward-halving-a-guide/
[April 7, 2013]
[8] Internet:
http://spectrum.ieee.org/tech-talk/computing/networks/bitcoin-
[April 7,2013]
[9] Internet:
http://blockchain.info/block/000000000000015c50b165fcdd33556f8b44800c5298943ac70b112df480c023

[April 7, 2013]
[10] Internet:
http://bitcoindifficulty.com
/ [April 7, 2013]
[11] Internet:
http://www.bitcoinx.com/profit/
[April 7, 2013]
[12] Internet:
http://www.butterflylabs.com
/ [April 7, 2013]
[13] Internet:
http://blockchain.info/pools
[April 7, 2013
[14] Internet:
http://blockchain.info/charts/hash-rate
[April 7, 2013]
Torque Final Report
24
Appendi x A: Proj ect Budget
Torque Final Report
25
Overview
Our combined budget cost is $108,344.77 for the 4 month duration of the project. This figure includes all of the hardware
expenses, software licensing costs, utility and rent costs as well as the labor time required to complete the project
requirements. This figure does not include GST or other fees.
Equipment & Facilities
Item
Amount
Cost
Combined Cost
Cisco 24 Port Gigabit Switch SGE2000
2
$699.99
$1,399.98
HP ProLiant DL385 G7 2U Servers
2
$4421
$8,842.00
HP ProLiant DL320 Server
1
$2000
$2,000
Core 2 Duo Computers
8
$239
$1,912.00
I7 Computers
2
$800
$1,600
Core 2 Quad Computers
2
$600
$1,200.00
Cabling
48
$8.99
$431.52
Surge Protector
5
$22.99
$114.95
Utilities
1
$1000/month
$4,000
Rent
1
$1000/month
$4,000
Server Racks
2
$634.16
$1,268.32
UPS 1500ABR
2
$300
$600.00
Laptops
3
$500
$1,500
8 port switch
1
$20
$20.00
Monitors
3
$150
$450.00
Extension Cord
1
$20
$20.00
Windows 2008 R2 License Enterprise
3
3,209
$9,627.00
ESXI License
10
$719
$7,190.00
Keyboards
4
$20
$80.00
Mice
4
$10
$40.00
KVM Switches
2
$100
$200.00
KVM Cables
8
$21.00
$168.00
Network Cards
9
$22
$198.00
Total
$46,861.77
Torque Final Report
26
Operating Costs
Item
Hours Needed
Days Spent
Rate per hour
Cost
Initial Documenting and research
112
14
$95
$10,604.00
Hardware Diagnostics and Repair
72
9
$110
$7,920.00
Networking setup
20
2.5
$140
$2,800.00
Software setup and installation
104
13
$120
$12,480.00
Testing and customization
56
7
$200
$11,200.00
Website building
56
7
$80
$4,480.00
Final documentation
24
3
$95
$2,280.00
Constructing Administrative Manual
40
5
$100
$4,000.00
VPN
16
1
$95
$1,520.00
Server configuration
8
1
$95
$760.00
VMware ESXI Install
20
10
$95
$1,900.00
VMware ESXI configuration Vcenter
8
1
$150
$1,200.00
NFS Server
1
1
$100
$100.00
Total
$61,244.00
Torque Final Report
27
Appendi x B: Gantt Chart
Torque Final Report
28
Torque Final Report
29
Torque Final Report
30
Torque Final Report
31
Torque Final Report
32
Torque Final Report
33
Torque Final Report
34
Appendi x C: Change Noti ces
Torque Final Report
35
Change Notice: Digital Excavation
Project Name:
Digital Excavation
Project Sponsor:
Tim Williams
Project Manager:
William Chan
Date Of Request:
2/10/2013
Date In Effect:
2/10/2013
Area of Change:
Scope Budget Schedule
Change Number:
1
Proposed Change
Description:
Project requirements of a VPN server needs to be set up and installed to gain network access outside of SAIT.
Justification:
Due to bit coin mining needing access to port 8333 and SAIT firewalls blocking that port, it is obligatory to gain access
to the outside network.
The most cost effective way to do this would be to setup a VPN in the security lab MD025, from there we can
use a VPN connection from anywhere on campus in order to gain access to the VPN server, and from the server we will
be able to access any ports that we wish to open.
Summary of Impact
Impacts of Not Implementing Proposed Change:
Impacts of Not Implementing Proposed Change:
We would not be able to test any of the bit coin mining software, due to the inability to sync with the network for verifica
-
tion.
We would not be able to test any of the bit coin mining software, due to the inability to sync with the network for verifica
-
tion.
Effects on Cost:
Effects on Cost:
Added cost would be applied to hardware which would equal to $400 for the system.
Labor applied to server setup would equal to a general estimate of around $300.
Added cost would be applied to hardware which would equal to $400 for the system.
Labor applied to server setup would equal to a general estimate of around $300.
Effect on Timescale:
Effect on Timescale:
Time required to configure this VPN would equal to about 16 hours in labor.
Effectively this can be done in line with tasks such as hardware setup.
Time required to configure this VPN would equal to about 16 hours in labor.
Effectively this can be done in line with tasks such as hardware setup.
Additional Resource Requirements
Additional Resource Requirements
None
None
Assessed By:
William Chan
Date:
2/11/2013
Torque Final Report
36
Change Notice: Digital Excavation
Project Name:
Digital Excavation
Project Sponsor:
Tim Williams
Project Manager:
William Chan
Date Of Request:
2/14/2013
Date In Effect:
2/14/2013
Area of Change:
Scope Schedule
Change Number:
2
Proposed Change
Description:
Project requirements of server services needed. We are required to setup a Microsoft Active Directory Server and Mem
-
ber server system on our network.
Justification
:
Due to changes in working with the systems that we are implementing, We require a Domain Controller and Member
server, as the software (VMware Vcenter) we are using for monitoring and system clustering is tightly integrated with Ac
-
tive directory.
Summary of Impact
Impacts of Not Implementing Proposed Change:
Not having this service could negatively impact our monitoring software, as it will not provide us with features that are
required to implement this software monitoring properly.
Effects on Cost:
The added cost would be applied to labor and licensing for software and for server setup. The estimated cost will be
around $500.
Effect on Timescale:
Time required to configure this server service would equal to about 1 day in labor.
Additional Resource Requirements
Additional Resource Requirements
None
None
Assessed By:
William Chan
Date:
2/14/2013
Torque Final Report
37
Change Notice: Digital Excavation
Project Name:
Digital Excavation
Project Sponsor:
Tim Williams
Project Manager:
William Chan
Date Of Request:
2/22/2013
Date In Effect:
2/22/2013
Area of Change:
Scope Schedule
Change Number:
3
Proposed Change
Description:
Project requirements of server services needed. We are required to setup a Network File System Server with proper
shares.
Justification:
Due to changes in working with the systems that we are implementing, We are required to have shared storage between
the virtual machines that we are using for cluster. With NFS we can implement this at a very low cost, with a high amount
of return. The feature Vmotion requires shared storage between machines in order to migrate Virtual Machines while
they are on.
Summary of Impact
Impacts of Not Implementing Proposed Change:
Not having this implemented can cause the system of balancing load on these machines in the cluster to be problematic.
Meaning that if we have to migrate virtual machines from one host to another it may take an extended amount of time,
and the machine required to be off in order to perform this action.
Effects on Cost:
The added cost would be applied to labor which would be $100.
Effect on Timescale:
Time required to configure this server service would equal to about 1 day in labor.
Additional Resource Requirements
Additional Resource Requirements
None
None
Assessed By:
William Chan
Date:
2/22/2013
Torque Final Report
38
Change Notice: Digital Excavation
Project Name:
Digital Excavation
Project Sponsor:
Tim Williams
Project Manager:
Christina Jewell
Date Of Request:
3/17/2013
Date In Effect:
3/17/2013
Area of Change:
Scope Budget Schedule
Change Number:
4
Proposed Change
Description:
Our expected goal of 50BTC will change to 25BTC.
Justification:
Due to the recent reward drop for mining one Bitcoin from 50BTC to 25BTC and the associated difficulty increase, our
scope will need to adjust accordingly.
Summary of Impact
Impacts of Not Implementing Proposed Change:
Impacts of Not Implementing Proposed Change:
We would likely not reach our intended goal, since now it would require twice and much work and time.
We would likely not reach our intended goal, since now it would require twice and much work and time.
Effects on Cost:
Effects on Cost:
Our initial expectation of 50BTC was based on solving one block, and at the time, 1BTC was valued at $10. Currently if
we solve one block, we receive 25BTC, currently valued at $50 each. Even with the scope change, solving one block will
produce more revenue.
Our initial expectation of 50BTC was based on solving one block, and at the time, 1BTC was valued at $10. Currently if
we solve one block, we receive 25BTC, currently valued at $50 each. Even with the scope change, solving one block will
produce more revenue.
Effect on Timescale:
Effect on Timescale:
Because of the increased difficulty, it will likely take more time to mine one block.
Because of the increased difficulty, it will likely take more time to mine one block.
Additional Resource Requirements
Additional Resource Requirements
None
None
Assessed By:
Christina Jewell
Date:
3/17/2013
Torque Final Report
39
Appendi x D: Hardware Speci fi cati ons
Torque Final Report
40
Make
Model
CPU
Motherboard
RAM
Storage
#of NIC
HP
DL385G7
AMD Opteron 6134
Server Board
12GB
146GB * 8
4
HP
DL385G7
AMD Opteron 6134
Server Board
8GB
146GB * 4
4
HP
DL320G4
3.4 Ghz Intel Pentium
Server Board
4GB
80GB * 2
2
Prodata
Performance
3.4 Ghz Core I7
Intel Boards
16Gb
2TB
2
Prodata
Performance
3.4 Ghz Core I7
Intel Boards
16Gb
2TB
2
Prodata
Performance
3.0 Ghz Core 2 Duo
Intel Boards
3GB
144GB
2
Prodata
Performance
3.0 Ghz Core 2 Duo
Intel Boards
3GB
144GB
2
Prodata
Performance
3.0 Ghz Core 2 Duo
Intel Boards
4GB
144GB
2
Prodata
Performance
3.0 Ghz Core 2 Duo
Intel Boards
4GB
69.5GB
2
Dell
Vostro 220
2.5GHZ Core 2 Quad
Dell
4GB
300GB
1
Dell
Vostro 220
2.5GHZ Core 2 Quad
Dell
4GB
300GB
2
Prodata
Performance
2.3GHZ Core 2 Duo
Intel Boards
4GB
144GB
2
Prodata
Performance
2.3GHZ Core 2 Duo
Intel Boards
4GB
144GB
2
Prodata
Performance
2.3GHZ Core 2 Duo
Intel Boards
4GB
144GB
2
Prodata
Performance
2.3GHZ Core 2 Duo
Intel Boards
4GB
144GB
2
Torque Final Report
41
Appendi x E: Networki ng Di agram
Torque Final Report
42
Torque Final Report
43
Appendi x D: Source Code
Torque Final Report
44
Bitcoind Main Header File (main.h)
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or
http://www.opensource.org/licenses/mit-license.php
.
#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
#include "bignum.h"
#include "sync.h"
#include "net.h"
#include "script.h"
#include <list>
class CWallet;
class CBlock;
class CBlockIndex;
class CKeyItem;
class CReserveKey;
class CAddress;
class CInv;
class CNode;
struct CBlockIndexWorkComparator;
/** The maximum allowed size for a serialized block, in bytes (network rule) */
static const unsigned int MAX_BLOCK_SIZE = 1000000;
/** The maximum size for mined blocks */
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
/** The maximum size for transactions we're willing to relay/mine */
static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
static const int64 MIN_TX_FEE = 50000;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */
static const int64 MIN_RELAY_TX_FEE = 10000;
/** No amount larger than this (in satoshi) is valid */
static const int64 MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
/** Maximum number of script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 16;
#ifdef USE_UPNP
static const int fHaveUPnP = true;
#else
static const int fHaveUPnP = false;
#endif
extern CScript COINBASE_FLAGS;
Torque Final Report
45
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid;
extern uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight;
extern CBigNum bnBestChainWork;
extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern uint64 nLastBlockTx;
extern uint64 nLastBlockSize;
extern const std::string strMessageMagic;
extern double dHashesPerSec;
extern int64 nHPSTimerStart;
extern int64 nTimeBestReceived;
extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
extern unsigned char pchMessageStart[4];
extern bool fImporting;
extern bool fReindex;
extern bool fBenchmark;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern unsigned int nCoinCacheSize;
// Settings
extern int64 nTransactionFee;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
class CReserveKey;
class CCoinsDB;
class CBlockTreeDB;
struct CDiskBlockPos;
class CCoins;
class CTxUndo;
class CCoinsView;
class CCoinsViewCache;
class CScriptCheck;
class CValidationState;
struct CBlockTemplate;
/** Register a wallet to receive updates from core */
void RegisterWallet(CWallet* pwalletIn);
/** Unregister a wallet from core */
void UnregisterWallet(CWallet* pwalletIn);
/** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate =
false);
/** Process an incoming block */
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64 nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Open an undo file (rev?????.dat) */
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Import blocks from an external file */
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
/** Initialize a new block tree database + block data on disk */
bool InitBlockIndex();
/** Load the block tree and coins database from disk */
bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
/** Verify consistency of the block and coin databases */
Torque Final Report
46
bool VerifyDB();
/** Print the loaded block tree */
void PrintBlockTree();
/** Find a block by height in the currently-connected chain */
CBlockIndex* FindBlockByHeight(int nHeight);
/** Process protocol messages received from a given node */
bool ProcessMessages(CNode* pfrom);
/** Send queued protocol messages to be sent to a give node */
bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(CReserveKey& reservekey);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
/** Do mining precalculation */
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
/** Check mined block */
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
/** Get the number of active peers */
int GetNumBlocksOfPeers();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */
std::string GetWarnings(std::string strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
/** Find the best known block, and make it the tip of the block chain */
bool ConnectBestBlock(CValidationState &state);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
/** Verify a signature */
bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int
nHashType);
/** Abort with a message */
bool AbortNode(const std::string &msg);
static inline std::string BlockHashStr(const uint256& hash)
{
return hash.ToString();
}
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
struct CDiskBlockPos
{
int nFile;
unsigned int nPos;
IMPLEMENT_SERIALIZE(
READWRITE(VARINT(nFile));
READWRITE(VARINT(nPos));
)
CDiskBlockPos() {
Torque Final Report
47
SetNull();
}
CDiskBlockPos(int nFileIn, unsigned int nPosIn) {
nFile = nFileIn;
nPos = nPosIn;
}
friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) {
return (a.nFile == b.nFile && a.nPos == b.nPos);
}
friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) {
return !(a == b);
}
void SetNull() { nFile = -1; nPos = 0; }
bool IsNull() const { return (nFile == -1); }
};
struct CDiskTxPos : public CDiskBlockPos
{
unsigned int nTxOffset; // after header
IMPLEMENT_SERIALIZE(
READWRITE(*(CDiskBlockPos*)this);
READWRITE(VARINT(nTxOffset));
)
CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos),
nTxOffset(nTxOffsetIn) {
}
CDiskTxPos() {
SetNull();
}
void SetNull() {
CDiskBlockPos::SetNull();
nTxOffset = 0;
}
};
/** An inpoint - a combination of a transaction and an index n into its vin */
class CInPoint
{
public:
CTransaction* ptx;
unsigned int n;
CInPoint() { SetNull(); }
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = (unsigned int) -1; }
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
};
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
public:
uint256 hash;
unsigned int n;
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { hash = 0; n = (unsigned int) -1; }
bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
Torque Final Report
48
{
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
friend bool operator!=(const COutPoint& a, const COutPoint& b)
{
return !(a == b);
}
std::string ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n);
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
/** An input of a transaction. It contains the location of the previous
* transaction's output that it claims and a signature that matches the
* output's public key.
*/
class CTxIn
{
public:
COutPoint prevout;
CScript scriptSig;
unsigned int nSequence;
CTxIn()
{
nSequence = std::numeric_limits<unsigned int>::max();
}
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int
nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = prevoutIn;
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int
nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = COutPoint(hashPrevTx, nOut);
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(nSequence);
)
bool IsFinal() const
{
return (nSequence == std::numeric_limits<unsigned int>::max());
}
friend bool operator==(const CTxIn& a, const CTxIn& b)
Torque Final Report
49
{
return (a.prevout == b.prevout &&
a.scriptSig == b.scriptSig &&
a.nSequence == b.nSequence);
}
friend bool operator!=(const CTxIn& a, const CTxIn& b)
{
return !(a == b);
}
std::string ToString() const
{
std::string str;
str += "CTxIn(";
str += prevout.ToString();
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
else
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
if (nSequence != std::numeric_limits<unsigned int>::max())
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
/** An output of a transaction. It contains the public key that the next input
* must be able to sign with to claim it.
*/
class CTxOut
{
public:
int64 nValue;
CScript scriptPubKey;
CTxOut()
{
SetNull();
}
CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
scriptPubKey = scriptPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(nValue);
READWRITE(scriptPubKey);
)
void SetNull()
{
nValue = -1;
scriptPubKey.clear();
}
bool IsNull() const
{
return (nValue == -1);
}
uint256 GetHash() const
Torque Final Report
50
{
return SerializeHash(*this);
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
{
return (a.nValue == b.nValue &&
a.scriptPubKey == b.scriptPubKey);
}
friend bool operator!=(const CTxOut& a, const CTxOut& b)
{
return !(a == b);
}
std::string ToString() const
{
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN,
scriptPubKey.ToString().substr(0,30).c_str());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
enum GetMinFee_mode
{
GMF_BLOCK,
GMF_RELAY,
GMF_SEND,
};
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
public:
static const int CURRENT_VERSION=1;
int nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
unsigned int nLockTime;
CTransaction()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
)
void SetNull()
{
nVersion = CTransaction::CURRENT_VERSION;
vin.clear();
vout.clear();
nLockTime = 0;
}
bool IsNull() const
Torque Final Report
51
{
return (vin.empty() && vout.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6
if (nLockTime == 0)
return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
}
bool IsNewerThan(const CTransaction& old) const
{
if (vin.size() != old.vin.size())
return false;
for (unsigned int i = 0; i < vin.size(); i++)
if (vin[i].prevout != old.vin[i].prevout)
return false;
bool fNewer = false;
unsigned int nLowest = std::numeric_limits<unsigned int>::max();
for (unsigned int i = 0; i < vin.size(); i++)
{
if (vin[i].nSequence != old.vin[i].nSequence)
{
if (vin[i].nSequence <= nLowest)
{
fNewer = false;
nLowest = vin[i].nSequence;
}
if (old.vin[i].nSequence < nLowest)
{
fNewer = true;
nLowest = old.vin[i].nSequence;
}
}
}
return fNewer;
}
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
}
/** Check for standard transaction types
@return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
bool IsStandard() const;
/** Check for standard transaction types
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return True if all inputs (scriptSigs) use only standard transaction forms
*/
bool AreInputsStandard(CCoinsViewCache& mapInputs) const;
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
@return number of sigops this transaction's outputs will produce when spent
Torque Final Report
52
*/
unsigned int GetLegacySigOpCount() const;
/** Count ECDSA signature operations in pay-to-script-hash inputs.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return maximum number of sigops required to validate this transaction's inputs
*/
unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const;
/** Amount of bitcoins spent by this transaction.
@return sum of all outputs (note: does not include fees)
*/
int64 GetValueOut() const
{
int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
nValueOut += txout.nValue;
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
}
return nValueOut;
}
/** Amount of bitcoins coming in to this transaction
Note that lightweight clients may not know anything besides the hash of previous transactions,
so may not be able to calculate this.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return Sum of value of all inputs (scriptSigs)
*/
int64 GetValueIn(CCoinsViewCache& mapInputs) const;
static bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
// need a fee.
return dPriority > COIN * 144 / 250;
}
int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK)
const;
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
return (a.nVersion == b.nVersion &&
a.vin == b.vin &&
a.vout == b.vout &&
a.nLockTime == b.nLockTime);
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
return !(a == b);
}
std::string ToString() const
{
std::string str;
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n",
GetHash().ToString().substr(0,10).c_str(),
nVersion,
vin.size(),
vout.size(),
nLockTime);
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (unsigned int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
Torque Final Report
53
void print() const
{
printf("%s", ToString().c_str());
}
// Check whether all prevouts of this transaction are present in the UTXO set represented by view
bool HaveInputs(CCoinsViewCache &view) const;
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline.
bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
std::vector<CScriptCheck> *pvChecks = NULL) const;
// Apply the effects of this transaction on the UTXO set represented by view
bool UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256
&txhash) const;
// Context-independent validity checks
bool CheckTransaction(CValidationState &state) const;
// Try to accept this transaction into the memory pool
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool*
pfMissingInputs=NULL);
protected:
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
};
/** wrapper for CTxOut that provides a more compact serialization */
class CTxOutCompressor
{
private:
CTxOut &txout;
public:
static uint64 CompressAmount(uint64 nAmount);
static uint64 DecompressAmount(uint64 nAmount);
CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
IMPLEMENT_SERIALIZE(({
if (!fRead) {
uint64 nVal = CompressAmount(txout.nValue);
READWRITE(VARINT(nVal));
} else {
uint64 nVal = 0;
READWRITE(VARINT(nVal));
txout.nValue = DecompressAmount(nVal);
}
CScriptCompressor cscript(REF(txout.scriptPubKey));
READWRITE(cscript);
});)
};
/** Undo information for a CTxIn
*
* Contains the prevout's CTxOut being spent, and if this was the
* last output of the affected transaction, its metadata as well
* (coinbase or not, height, transaction version)
*/
class CTxInUndo
{
public:
CTxOut txout; // the txout data before being spent
bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase
unsigned int nHeight; // if the outpoint was the last unspent: its height
int nVersion; // if the outpoint was the last unspent: its version
CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {}
Torque Final Report
54
CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) :
txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { }
unsigned int GetSerializeSize(int nType, int nVersion) const {
return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) +
(nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) +
::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion);
}
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersion) const {
::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion);
if (nHeight > 0)
::Serialize(s, VARINT(this->nVersion), nType, nVersion);
::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream &s, int nType, int nVersion) {
unsigned int nCode = 0;
::Unserialize(s, VARINT(nCode), nType, nVersion);
nHeight = nCode / 2;
fCoinBase = nCode & 1;
if (nHeight > 0)
::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion);
}
};
/** Undo information for a CTransaction */
class CTxUndo
{
public:
// undo information for all txins
std::vector<CTxInUndo> vprevout;
IMPLEMENT_SERIALIZE(
READWRITE(vprevout);
)
};
/** Undo information for a CBlock */
class CBlockUndo
{
public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase
IMPLEMENT_SERIALIZE(
READWRITE(vtxundo);
)
bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to append
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (!fileout)
return error("CBlockUndo::WriteToDisk() : OpenUndoFile failed");
// Write index header
unsigned int nSize = fileout.GetSerializeSize(*this);
fileout << FLATDATA(pchMessageStart) << nSize;
// Write undo data
long fileOutPos = ftell(fileout);
if (fileOutPos < 0)
return error("CBlockUndo::WriteToDisk() : ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << *this;
// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << *this;
Torque Final Report
55
fileout << hasher.GetHash();
// Flush stdio buffers and commit to disk before returning
fflush(fileout);
if (!IsInitialBlockDownload())
FileCommit(fileout);
return true;
}
bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to read
CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CBlockUndo::ReadFromDisk() : OpenBlockFile failed");
// Read block
uint256 hashChecksum;
try {
filein >> *this;
filein >> hashChecksum;
}
catch (std::exception &e) {
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
}
// Verify checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << *this;
if (hashChecksum != hasher.GetHash())
return error("CBlockUndo::ReadFromDisk() : checksum mismatch");
return true;
}
};
/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
*
* Serialized format:
* - VARINT(nVersion)
* - VARINT(nCode)
* - unspentness bitvector, for vout[2] and further; least significant byte first
* - the non-spent CTxOuts (via CTxOutCompressor)
* - VARINT(nHeight)
*
* The nCode value consists of:
* - bit 1: IsCoinBase()
* - bit 2: vout[0] is not spent
* - bit 4: vout[1] is not spent
* - The higher bits encode N, the number of non-zero bytes in the following bitvector.
* - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
* least one non-spent output).
*
* Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
* <><><--------------------------------------------><---->
* | \ | /
* version code vout[1] height
*
* - version = 1
* - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
* - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
* - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
* * 8358: compact amount representation for 60000000000 (600 BTC)
* * 00: special txout type pay-to-pubkey-hash
* * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
* - height = 203998
*
*
* Example:
0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17
e7f9555caa486af3b
Torque Final Report
56
* <><><--><--------------------------------------------------><----------------------------------------------><---->
* / \ \ | | /
* version code unspentness vout[4] vout[16] height
*
* - version = 1
* - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
* 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
* - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
* - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
* * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
* * 00: special txout type pay-to-pubkey-hash
* * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
* - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
* * bbd123: compact amount representation for 110397 (0.001 BTC)
* * 00: special txout type pay-to-pubkey-hash
* * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
* - height = 120891
*/
class CCoins
{
public:
// whether transaction is a coinbase
bool fCoinBase;
// unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
std::vector<CTxOut> vout;
// at which height this transaction was included in the active block chain
int nHeight;
// version of the CTransaction; accesses to this value should probably check for nHeight as well,
// as new tx version will probably only be introduced at certain heights
int nVersion;
// construct a CCoins from a CTransaction, at a given height
CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn),
nVersion(tx.nVersion) { }
// empty constructor
CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
// remove spent outputs at the end of vout
void Cleanup() {
while (vout.size() > 0 && vout.back().IsNull())
vout.pop_back();
if (vout.empty())
std::vector<CTxOut>().swap(vout);
}
void swap(CCoins &to) {
std::swap(to.fCoinBase, fCoinBase);
to.vout.swap(vout);
std::swap(to.nHeight, nHeight);
std::swap(to.nVersion, nVersion);
}
// equality test
friend bool operator==(const CCoins &a, const CCoins &b) {
return a.fCoinBase == b.fCoinBase &&
a.nHeight == b.nHeight &&
a.nVersion == b.nVersion &&
a.vout == b.vout;
}
friend bool operator!=(const CCoins &a, const CCoins &b) {
return !(a == b);
}
// calculate number of bytes for the bitmask, and its number of non-zero bytes
// each bit in the bitmask represents the availability of one output, but the
// availabilities of the first two outputs are encoded separately
void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
unsigned int nLastUsedByte = 0;
for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
Torque Final Report
57
bool fZero = true;
for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
if (!vout[2+b*8+i].IsNull()) {
fZero = false;
continue;
}
}
if (!fZero) {
nLastUsedByte = b + 1;
nNonzeroBytes++;
}
}
nBytes += nLastUsedByte;
}
bool IsCoinBase() const {
return fCoinBase;
}
unsigned int GetSerializeSize(int nType, int nVersion) const {
unsigned int nSize = 0;
unsigned int nMaskSize = 0, nMaskCode = 0;
CalcMaskSize(nMaskSize, nMaskCode);
bool fFirst = vout.size() > 0 && !vout[0].IsNull();
bool fSecond = vout.size() > 1 && !vout[1].IsNull();
assert(fFirst || fSecond || nMaskCode);
unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ?
4 : 0);
// version
nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
// size of header code
nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
// spentness bitmask
nSize += nMaskSize;
// txouts themself
for (unsigned int i = 0; i < vout.size(); i++)
if (!vout[i].IsNull())
nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
// height
nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
return nSize;
}
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersion) const {
unsigned int nMaskSize = 0, nMaskCode = 0;
CalcMaskSize(nMaskSize, nMaskCode);
bool fFirst = vout.size() > 0 && !vout[0].IsNull();
bool fSecond = vout.size() > 1 && !vout[1].IsNull();
assert(fFirst || fSecond || nMaskCode);
unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ?
4 : 0);
// version
::Serialize(s, VARINT(this->nVersion), nType, nVersion);
// header code
::Serialize(s, VARINT(nCode), nType, nVersion);
// spentness bitmask
for (unsigned int b = 0; b<nMaskSize; b++) {
unsigned char chAvail = 0;
for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
if (!vout[2+b*8+i].IsNull())
chAvail |= (1 << i);
::Serialize(s, chAvail, nType, nVersion);
}
// txouts themself
for (unsigned int i = 0; i < vout.size(); i++) {
if (!vout[i].IsNull())
::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
}
// coinbase height
::Serialize(s, VARINT(nHeight), nType, nVersion);
}
Torque Final Report
58
template<typename Stream>
void Unserialize(Stream &s, int nType, int nVersion) {
unsigned int nCode = 0;
// version
::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
// header code
::Unserialize(s, VARINT(nCode), nType, nVersion);
fCoinBase = nCode & 1;
std::vector<bool> vAvail(2, false);
vAvail[0] = nCode & 2;
vAvail[1] = nCode & 4;
unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
// spentness bitmask
while (nMaskCode > 0) {
unsigned char chAvail = 0;
::Unserialize(s, chAvail, nType, nVersion);
for (unsigned int p = 0; p < 8; p++) {
bool f = (chAvail & (1 << p)) != 0;
vAvail.push_back(f);
}
if (chAvail != 0)
nMaskCode--;
}
// txouts themself
vout.assign(vAvail.size(), CTxOut());
for (unsigned int i = 0; i < vAvail.size(); i++) {
if (vAvail[i])
::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
}
// coinbase height
::Unserialize(s, VARINT(nHeight), nType, nVersion);
Cleanup();
}
// mark an outpoint spent, and construct undo information
bool Spend(const COutPoint &out, CTxInUndo &undo) {
if (out.n >= vout.size())
return false;
if (vout[out.n].IsNull())
return false;
undo = CTxInUndo(vout[out.n]);
vout[out.n].SetNull();
Cleanup();
if (vout.size() == 0) {
undo.nHeight = nHeight;
undo.fCoinBase = fCoinBase;
undo.nVersion = this->nVersion;
}
return true;
}
// mark a vout spent
bool Spend(int nPos) {
CTxInUndo undo;
COutPoint out(0, nPos);
return Spend(out, undo);
}
// check whether a particular output is still available
bool IsAvailable(unsigned int nPos) const {
return (nPos < vout.size() && !vout[nPos].IsNull());
}
// check whether the entire CCoins is spent
// note that only !IsPruned() CCoins can be serialized
bool IsPruned() const {
BOOST_FOREACH(const CTxOut &out, vout)
if (!out.IsNull())
return false;
return true;
}
};
Torque Final Report
59
/** Closure representing one script verification
* Note that this stores references to the spending transaction */
class CScriptCheck
{
private:
CScript scriptPubKey;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
int nHashType;
public:
CScriptCheck() {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int
nHashTypeIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { }
bool operator()() const;
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(nHashType, check.nHashType);
}
};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
public:
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
// memory only
mutable bool fMerkleVerified;
CMerkleTx()
{
Init();
}
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
{
Init();
}
void Init()
{
hashBlock = 0;
nIndex = -1;
fMerkleVerified = false;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int SetMerkleBranch(const CBlock* pblock=NULL);
int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
Torque Final Report
60
int GetBlocksToMaturity() const;
bool AcceptToMemoryPool(bool fCheckInputs=true, bool fLimitFree=true);
};
/** Data structure that represents a partial merkle tree.
*
* It respresents a subset of the txid's of a known block, in a way that
* allows recovery of the list of txid's and the merkle root, in an
* authenticated way.
*
* The encoding works as follows: we traverse the tree in depth-first order,
* storing a bit for each traversed node, signifying whether the node is the
* parent of at least one matched leaf txid (or a matched txid itself). In
* case we are at the leaf level, or this bit is 0, its merkle node hash is
* stored, and its children are not explorer further. Otherwise, no hash is
* stored, but we recurse into both (or the only) child branch. During
* decoding, the same depth-first traversal is performed, consuming bits and
* hashes as they written during encoding.
*
* The serialization is fixed and provides a hard guarantee about the
* encoded size:
*
* SIZE <= 10 + ceil(32.25*N)
*
* Where N represents the number of leaf nodes of the partial tree. N itself
* is bounded by:
*
* N <= total_transactions
* N <= 1 + matched_transactions*tree_height
*
* The serialization format:
* - uint32 total_transactions (4 bytes)
* - varint number of hashes (1-3 bytes)
* - uint256[] hashes in depth-first order (<= 32*N bytes)
* - varint number of bytes of flag bits (1-3 bytes)
* - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
* The size constraints follow from this.
*/
class CPartialMerkleTree
{
protected:
// the total number of transactions in the block
unsigned int nTransactions;
// node-is-parent-of-matched-txid bits
std::vector<bool> vBits;
// txids and internal hashes
std::vector<uint256> vHash;
// flag set when encountering invalid data
bool fBad;
// helper function to efficiently calculate the number of nodes at given height in the merkle tree
unsigned int CalcTreeWidth(int height) {
return (nTransactions+(1 << height)-1) >> height;
}
// calculate the hash of a node in the merkle tree (at leaf level: the txid's themself)
uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
// recursive function that traverses tree nodes, storing the data as bits and hashes
void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool>
&vMatch);
// recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
// it returns the hash of the respective node.
uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed,
std::vector<uint256> &vMatch);
Torque Final Report
61
public:
// serialization implementation
IMPLEMENT_SERIALIZE(
READWRITE(nTransactions);
READWRITE(vHash);
std::vector<unsigned char> vBytes;
if (fRead) {
READWRITE(vBytes);
CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
us.vBits.resize(vBytes.size() * 8);
for (unsigned int p = 0; p < us.vBits.size(); p++)
us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
us.fBad = false;
} else {
vBytes.resize((vBits.size()+7)/8);
for (unsigned int p = 0; p < vBits.size(); p++)
vBytes[p / 8] |= vBits[p] << (p % 8);
READWRITE(vBytes);
}
)
// Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them
CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
CPartialMerkleTree();
// extract the matching txid's represented by this partial merkle tree.
// returns the merkle root, or 0 in case of failure
uint256 ExtractMatches(std::vector<uint256> &vMatch);
};
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
* to everyone and the block is added to the block chain. The first transaction
* in the block is a special one that creates a new coin owned by the creator
* of the block.
*/
class CBlockHeader
{
public:
// header
static const int CURRENT_VERSION=2;
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
CBlockHeader()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
)
void SetNull()
{
nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock = 0;
Torque Final Report
62
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
}
bool IsNull() const
{
return (nBits == 0);
}
uint256 GetHash() const
{
return Hash(BEGIN(nVersion), END(nNonce));
}
int64 GetBlockTime() const
{
return (int64)nTime;
}
void UpdateTime(const CBlockIndex* pindexPrev);
};
class CBlock : public CBlockHeader
{
public:
// network and disk
std::vector<CTransaction> vtx;
// memory only
mutable std::vector<uint256> vMerkleTree;
CBlock()
{
SetNull();
}
CBlock(const CBlockHeader &header)
{
SetNull();
*((CBlockHeader*)this) = header;
}
IMPLEMENT_SERIALIZE
(
READWRITE(*(CBlockHeader*)this);
READWRITE(vtx);
)
void SetNull()
{
CBlockHeader::SetNull();
vtx.clear();
vMerkleTree.clear();
}
CBlockHeader GetBlockHeader() const
{
CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
}
uint256 BuildMerkleTree() const
{
vMerkleTree.clear();
BOOST_FOREACH(const CTransaction& tx, vtx)
Torque Final Report
63
vMerkleTree.push_back(tx.GetHash());
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
int i2 = std::min(i+1, nSize-1);
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
}
j += nSize;
}
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
const uint256 &GetTxHash(unsigned int nIndex) const {
assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
assert(nIndex < vtx.size());
return vMerkleTree[nIndex];
}
std::vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
std::vector<uint256> vMerkleBranch;
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
int i = std::min(nIndex^1, nSize-1);
vMerkleBranch.push_back(vMerkleTree[j+i]);
nIndex >>= 1;
j += nSize;
}
return vMerkleBranch;
}
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
if (nIndex == -1)
return 0;
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
{
if (nIndex & 1)
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
else
hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
nIndex >>= 1;
}
return hash;
}
bool WriteToDisk(CDiskBlockPos &pos)
{
// Open history file to append
CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
if (!fileout)
return error("CBlock::WriteToDisk() : OpenBlockFile failed");