예제 #1
0
	def payment_key(self):
		'''Generates the Payment Transaction Key, or PTK. It does not communicate with the server.'''

		#------------------------------------
		#        PTK Payload v1 Block
		#------------------------------------

		p1 = pcos.create_output_block( 'P1' )
		# membership ID
		device_id = self.args['device_id'] 
		p1.write_string( device_id )

		#------------------------------------
		#        PTK M1HW Block
		#------------------------------------

		m1hw = pcos.create_output_block( 'M1' )

		# tag serial number
		m1hw.write_bytestr( binascii.unhexlify(self.args['serial_number']) )

		# app challenge seed
		m1hw.write_bytestr( binascii.unhexlify(self.args['seed']) )

		# transaction key ID
		m1hw.write_bytes( binascii.unhexlify(self.args['keyid']) )

		# PUF response
		m1hw.write_bytestr( binascii.unhexlify(self.args['puf_response']) )

		# fake challenge-response time (ms)
		m1hw.write_uint( 92 )

		#------------------------------------
		# PTK Message
		#  * Payload Block
		#  * M1HW Block
		#------------------------------------
		ptk = pcos.Doc( name="PaymentKey" )
		ptk.add( p1 )
		ptk.add( m1hw )
		ptk_bytes = ptk.as_bytearray()

		# write serialized data as binary and qr-code
		payload_file = open('ptk.pcos', 'w')
		payload_file.write( ptk_bytes )
		payload_file.close()
		print ("Saved PTK object to 'ptk.pcos'")

		return ptk_bytes
예제 #2
0
	def transfer(self):
		'''Sends a Transfer Request'''

		apta_bytes = self.payment()

		#------------------------------------
		#      Armored-PTA Block
		#------------------------------------
		apta_block = pcos.create_output_block( 'Pa' )

		# we use "fixstr" becase we don't want size-prefix
		apta_block.write_fixstr(apta_bytes, len(apta_bytes))

		#------------------------------------
		#      Transfer Request Block
		#------------------------------------
		trnfs_req_block = pcos.create_output_block( 'R1' ) 

		# mat
		trnfs_req_block.write_varstr( binascii.unhexlify( self.args['receiver_mat'] ) )

		# ref data
		trnfs_req_block.write_varstr( '' )

		# create-time
		trnfs_req_block.write_ulong( long( time.time() + 0.5 ) )

		(charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge']))
		trnfs_req_block.write_long( charge_int ) # value
		trnfs_req_block.write_int( charge_scale ) # scale

		# currency
		trnfs_req_block.write_fixstr( "USD", size=3 )
 
		# note
		trnfs_req_block.write_varstr( 'John paid his dept' )

		# no geo-location available
		trnfs_req_block.write_bool(False)

		#------------------------------------
		#      Transfer Message
		#------------------------------------
		req = pcos.Doc( name="Tt" )
		req.add( trnfs_req_block )
		req.add( apta_block )

		res = self.send( req )
		self.expect_success( res )
예제 #3
0
	def balance(self):
		'''Returns account balance'''

		#------------------------------------
		#      Request Body Block
		#------------------------------------
		out_bo = pcos.create_output_block( 'Bo' )
		out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) ) # mat
		out_bo.write_varstr( '' ) # ref_data

		req = pcos.Doc( name="Bq" )
		req.add( out_bo )

		res = self.send( req )

		assert res.message_id == 'Br'

		#------------------------------------
		#      Response Body Block
		#------------------------------------
		body = res.block( 'Bo' )
		ref_data = body.read_varstr( ) # ref_data

		value = body.read_long() # value
		scale = body.read_int() # scale
		balance_asofepoch = body.read_ulong();

		balance = value * math.pow(10, scale)
		balance_asofdate = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(balance_asofepoch))
		log.info('Balance is $%s as of %s', balance, balance_asofdate)
예제 #4
0
	def provision(self):
		'''Provision a device'''

		#------------------------------------
		#           Body Block
		#------------------------------------
		out_bo = pcos.create_output_block( 'Bo' )

		# MAT
		out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) )
		# Serial number ID
		out_bo.write_varstr( binascii.unhexlify(self.args['serial_number']) )

		#------------------------------------
		#       Provision Message
		#------------------------------------
		req = pcos.Doc( name="Ov" )
		req.add( out_bo )

		# send the message and process the result.
		res = self.send( req )

		self.expect_message(res, 'Cr')

		# jump to the block of interest
		in_bo = res.block( 'Bo' )

		# read MAT returned by the server
		device_id = in_bo.read_varstr()
		registration_id =in_bo.read_varstr()

		log.info('provision-success| device-ID: %s, registration-ID: %s', binascii.hexlify( device_id ), registration_id )
예제 #5
0
	def preauth(self):
		'''Generates the PTA and submits to server for validation.'''
		apta_bytes = self.payment()

		#------------------------------------
		#      Armored-PTA Block
		#------------------------------------
		apta_block = pcos.create_output_block( 'Pa' )

		# we use "fixstr" becase we don't want size-prefix
		apta_block.write_fixstr(apta_bytes, len(apta_bytes))

		#------------------------------------
		#      Preauthorizaton Block
		#------------------------------------
		preauth_block = pcos.create_output_block( 'Pr' ) 
		# mat
		preauth_block.write_varstr( binascii.unhexlify( self.args['preauth_mat'] ) )

		# ref data
		preauth_block.write_varstr( '' )

		# preauth amount
		(charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge']))
		preauth_block.write_long( charge_int ) # value
		preauth_block.write_int( charge_scale ) # scale

		# currency
		preauth_block.write_fixstr( "USD", size=3 )

		#------------------------------------
		#      Preauth Message
		#------------------------------------
		req = pcos.Doc( name="Pr" )
		req.add( preauth_block )
		req.add( apta_block )

		res = self.send( req )
		self.expect_success( res )
예제 #6
0
	def register(self):
		'''Register command'''

		#------------------------------------
		#           Body Block
		#------------------------------------
		bo = pcos.create_output_block( 'Bo' )

		# registration ID
		bo.write_string( self.args['registration_id'] )

		# DER encoded public key -- signature verification key
		bo.write_bytestr( base64.b64decode(TEST_DSA_KEY_PUB_PEM) )

		# # user-agent attributes
		# user_agent = [
		# 	('appname', 'IceBreaker'), 
		# 	('appver', '2.0'), 
		# 	('appurl', 'https://pushcoin.com/Pub/SDK/WelcomeDevelopers'), 
		# 	('author', 'PushCoin <*****@*****.**>'), 
		# 	('os', '%s %s' % (sys.platform, sys.version)), 
		# ]
		# bo.write_uint( len(user_agent) )
		# for kv in user_agent:
		# 	bo.write_varstr( kv[0] )
		# 	bo.write_varstr( kv[1] )

		#------------------------------------
		#       Register Message
		#------------------------------------
		req = pcos.Doc( name="Re" )
		req.add( bo )

		# send the message and process the result.
		res = self.send( req )

		assert res.message_id == 'Ac'
		# jump to the block of interest
		out_bo = res.block( 'Bo' )

		# read MAT returned by the server
		mat = out_bo.read_bytestr()

		log.info('Success (MAT: %s)', binascii.hexlify( mat ))
예제 #7
0
	def error_report(self):
		'''Submits an error report'''

		#------------------------------------
		#      Request Body Block
		#------------------------------------
		out_bo = pcos.create_output_block( 'Bo' )
		# MAT
		out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) )
		# mime
		out_bo.write_string( 'text/plain'  )
		# report content
		out_bo.write_bytestr( self.args['report']  )

		req = pcos.Doc( name="Er" )
		req.add( out_bo )

		res = self.send( req )
		self.expect_success( res )
예제 #8
0
	def transaction_challenge(self):

		req = pcos.Doc( name="Tc" )
		out_bo = pcos.create_output_block( 'Bo' )
		out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) )
		req.add( out_bo )
		res = self.send( req )

		# jump to the block of interest
		body = res.block( 'Bo' )

		# number of keys
		challenge_count = body.read_uint()

		for ix in xrange(0,challenge_count):
			response_length = body.read_uint()
			challenge = body.read_bytestr()
			challenge_id = body.read_bytestr()
			key_expiry = body.read_ulong()
			log.info('challenge %s, ID %s, expires on %s, exp-response-length: %s', binascii.hexlify( challenge), binascii.hexlify( challenge_id ), time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(key_expiry)), response_length)
예제 #9
0
	def payment_pta(self):
		'''Generates the Payment Transaction Authorization, or PTA. It does not communicate with the server.'''

		#------------------------------------
		#        PTA Payment Block
		#------------------------------------
		p1 = pcos.create_output_block( 'P1' )

		# member authentication token
		mat = self.args['mat'] 
		if len( mat ) != 40:
			raise RuntimeError("MAT must be 40-characters long" % self.cmd)
		p1.write_varstr( binascii.unhexlify( mat ) )

		# cert. create time and expiry
		now = long( time.time() + 0.5 )
		p1.write_ulong( now ) # certificate create-time
		p1.write_ulong( now + 24 * 3600 ) # certificate expires in 24 hrs

		# payment-limit
		(payment_int, payment_scale) = decimal_to_parts(Decimal(self.args['limit']))
		p1.write_long( payment_int ) # value
		p1.write_int( payment_scale ) # scale

		# currency
		p1.write_fixstr( "USD", size=3 )

		# recipient
		p1.write_varstr( "" )

		# ref-data
		p1.write_varstr( "" )

		# note
		p1.write_varstr( "" )

		print (" %s bytes => Payment Block" % p1.size())

		#------------------------------------
		#        PTA Signature Block
		#------------------------------------
		s1 = pcos.create_output_block( 'S1' )

		# checksum Payment Block
		digest = hashlib.sha1(p1.as_bytearray()).digest()
		
		# sign the checksum
		dsa_priv_key = BIO.MemoryBuffer( TEST_DSA_KEY_PRV_PEM )
		signer = DSA.load_key_bio( dsa_priv_key )
		signature = signer.sign_asn1( digest )

		# store the signature of the Payment Block
		s1.write_varstr( signature )
		print (" %s bytes => Signature Block" % s1.size())

		#------------------------------------
		# PTA Message
		#  * Payment Block
		#  * Signature Block
		#------------------------------------
		pta = pcos.Doc( name="Pa" )
		pta.add( p1 )
		pta.add( s1 )

		#------------------------------------
		#    A-PTA Private (PTA) Block
		#------------------------------------
		a1 = pcos.create_output_block( 'A1' )
		
		# encrypt the PTA message
		txn_pub_key = BIO.MemoryBuffer( API_TRANSACTION_KEY_PEM )
		encrypter = RSA.load_pub_key_bio( txn_pub_key )
		# RSA Encryption Scheme w/ Optimal Asymmetric Encryption Padding
		input_data = pta.as_bytearray()
		print (" %s bytes => header+meta" % (len(input_data) - s1.size() - p1.size()))
		print ("-------------\n %s bytes => Total PTA\n---------" % len(input_data))
		encrypted = encrypter.public_encrypt( pta.as_bytearray(), RSA.pkcs1_padding )
		a1.write_fixstr( encrypted, size=len(encrypted) )

		#------------------------------------
		#    A-PTA Public Block
		#------------------------------------
		k1 = pcos.create_output_block( 'K1' )
		# encryption key identifier
		k1.write_fixstr( API_TRANSACTION_KEY_ID, size=len(API_TRANSACTION_KEY_ID) )

		#------------------------------------
		#    A-PTA Message
		#------------------------------------
		apta = pcos.Doc( name="Ap" )
		apta.add( a1 )
		apta.add( k1 )
		apta_bytes = apta.as_bytearray()

		# write serialized data as binary and qr-code
		payload_file = open('apta.pcos', 'w')
		payload_file.write( apta_bytes )
		payload_file.close()
		print ("Saved APTA object to 'apta.pcos'")

		# optionally generate qr-code
		try:
			import qrcode
			qr = qrcode.QRCode(version=None, box_size=3, error_correction=qrcode.constants.ERROR_CORRECT_L)
			qr.add_data( apta_bytes )
			qr.make(fit=True)
			img = qr.make_image()
			img.save('apta.png')
			print ("APTA-QR: apta.png, version %s" % (qr.version))
		except ImportError:
			log.warn("QR-Code not written -- qrcode module not found")

		return apta_bytes
예제 #10
0
	def payment_key(self):
		'''Generates the Payment Transaction Key, or PTK. It does not communicate with the server.'''

		#------------------------------------
		#        PTK Key Block
		#------------------------------------

		k1 = pcos.create_output_block( 'K1' )
		# membership ID
		device_id = self.args['device_id'] 
		k1.write_varstr( device_id )

		# passcode
		k1.write_varstr( self.args['passcode'] )

		# key create time and expiry
		now = long( time.time() + 0.5 )

		# utc_ctime
		k1.write_ulong( now ) # key create-time

		# transaction footprint queue
		k1.write_bool( True )
		footprint = binascii.unhexlify(self.args['footprint'])
		# write transaction queue
		k1.write_uint( 10 )
		for i in xrange(0,10):
			k1.write_fixstr( footprint, 4 )

		# counter
		k1.write_uint( 0 ) 

		# source_id (aka serial number)
		k1.write_varstr( binascii.unhexlify(self.args['serial_number']) )

		print (" %s bytes => Key Block" % k1.size())

		#------------------------------------
		#        PTK Checksum Block
		#------------------------------------
		c1 = pcos.create_output_block( 'C1' )

		# checksum Key Block
		digest = hashlib.sha1(k1.as_bytearray()).digest()

		# store the signature of the Payment Block
		c1.write_varstr( digest )
		print (" %s bytes => Checksum Block" % c1.size())

		#------------------------------------
		# PTK Message
		#  * Key Block
		#  * Checksum Block
		#------------------------------------
		ptk = pcos.Doc( name="Pk" )
		ptk.add( k1 )
		ptk.add( c1 )
		ptk_bytes = ptk.as_bytearray()

		# write serialized data as binary and qr-code
		payload_file = open('ptk.pcos', 'w')
		payload_file.write( ptk_bytes )
		payload_file.close()
		print ("Saved PTK object to 'ptk.pcos'")

		return ptk_bytes
예제 #11
0
	def charge(self, payment_type, payment_bytes):
		#------------------------------------
		#      Payment Block
		#------------------------------------
		payment_block = pcos.create_output_block( payment_type )

		# we use "fixstr" becase we don't want size-prefix
		payment_block.write_fixstr(payment_bytes, len(payment_bytes))

		#------------------------------------
		#      Payment Request Block
		#------------------------------------
		paymnt_req_block = pcos.create_output_block( 'R1' ) 

		# mat
		paymnt_req_block.write_varstr( binascii.unhexlify( self.args['receiver_mat'] ) )

		# ref data
		paymnt_req_block.write_varstr( '' )

		# create-time
		paymnt_req_block.write_ulong( long( time.time() + 0.5 ) )

		(charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge']))
		paymnt_req_block.write_long( charge_int ) # value
		paymnt_req_block.write_int( charge_scale ) # scale

		# tax
		paymnt_req_block.write_bool(True) # optional indicator
		(tax_value, tax_scale) = decimal_to_parts(Decimal(self.args['tax']))
		paymnt_req_block.write_long( tax_value ) # value
		paymnt_req_block.write_int( tax_scale ) # scale

		# tip
		paymnt_req_block.write_bool(True) # optional indicator
		(tip_value, tip_scale) = decimal_to_parts(Decimal(self.args['tip']))
		paymnt_req_block.write_long( tip_value ) # value
		paymnt_req_block.write_int( tip_scale ) # scale

		# currency
		paymnt_req_block.write_fixstr( "USD", size=3 )

		# invoice ID
		paymnt_req_block.write_varstr( 'inv-123' )

		# note
		paymnt_req_block.write_varstr( 'happy meal' )

		# no geo-location available
		paymnt_req_block.write_bool(False)

		# list of purchased goods
		paymnt_req_block.write_int(0)

		#------------------------------------
		#   Payment Request Signature Block
		#------------------------------------

		paymnt_req_signature_block = pcos.create_output_block( 'S1' )

		# checksum Payment Request Block
		digest = hashlib.sha1(paymnt_req_block.as_bytearray()).digest()
		
		# sign the checksum
		dsa_priv_key = BIO.MemoryBuffer( TEST_DSA_KEY_PRV_PEM )
		signer = DSA.load_key_bio( dsa_priv_key )
		signature = signer.sign_asn1( digest )

		# store the signature of the Payment Block
		paymnt_req_signature_block.write_varstr( signature )

		#------------------------------------
		#      Payment Request Message
		#------------------------------------
		req = pcos.Doc( name="Pt" )
		req.add( paymnt_req_block )
		req.add( paymnt_req_signature_block )
		req.add( payment_block )

		res = self.send( req )
		
		# there can be two types of results: Ap or Np, depending
		# success or failure due to insufficient funds
		if res.message_id != 'Ap' and res.message_id != 'Np':
			raise RuntimeError("Unexpected payment result '%s'" % res.message_id)
		
		# read balance
		balance = res.block( 'Bo' )
		ref_data = balance.read_varstr() # ref_data
		transaction_id = balance.read_varstr() # tx-id

		if res.message_id == 'Np':
			code = er.read_uint()
			what = er.read_varstr()
			
		# exact amount given?
		if balance.read_bool():
			exact_balance = 'is'
		else:
			exact_balance = 'is greater than' 
		# amount
		value = balance.read_long() # value
		scale = balance.read_int() # scale
		balance_amount = value * math.pow(10, scale)
		# time of last update
		tm_epoch = balance.read_ulong();
		balance_asofdate = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(tm_epoch))

		if res.message_id == 'Np':
			log.warn('%s (tx_id: %s). Balance %s $%s as of %s', what, base64.b32encode(transaction_id), exact_balance, balance_amount, balance_asofdate)
		else:
			log.info('Success (tx_id: %s). Balance %s $%s as of %s', base64.b32encode(transaction_id), exact_balance, balance_amount, balance_asofdate)
예제 #12
0
	def history(self):
		'''Returns transaction history'''

		#------------------------------------
		#      Request Body Block
		#------------------------------------
		out_bo = pcos.create_output_block( 'Bo' )
		# MAT
		out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) )
		# ref-data
		out_bo.write_varstr( '' )
		# search keywords
		out_bo.write_varstr( '' )

		# page number and page-size
		out_bo.write_uint( int(self.args['page']) )
		out_bo.write_uint( int(self.args['size']) )

		#------------------------------------
		#    History Query Message
		#------------------------------------
		req = pcos.Doc( name="Hq" )
		req.add( out_bo )

		res = self.send( req )

		assert res.message_id == 'Hr'

		#------------------------------------
		#      Response Body Block
		#------------------------------------
		body = res.block( 'Bo' )
		# ref-data
		ref_data = body.read_varstr()

		# read number of transactions
		count = body.read_uint()
		for i in xrange(1, count+1):
			# transaction ID
			tx_id = binascii.hexlify( body.read_varstr() )

			# counterparty ID
			counterparty = binascii.hexlify( body.read_varstr() )

			# transaction time of day
			epoch_tx_time = body.read_ulong()
			tx_time = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(epoch_tx_time))

			# transaction type
			tx_type = body.read_fixstr(1)

			# transaction context: (P)ayment or (T)ransfer
			tx_context = body.read_fixstr(1)

			#amount
			value = body.read_long() # value
			scale = body.read_int() # scale
			amount = value * math.pow(10, scale)

			# tax
			if body.read_bool():
				value = body.read_long() # value
				scale = body.read_int() # scale
				tax = value * math.pow(10, scale)
			else:
				tax = 'not provided'

			#tip
			if body.read_bool():
				value = body.read_long() # value
				scale = body.read_int() # scale
				tip = value * math.pow(10, scale)
			else:
				tip = 'not provided'

			# currency
			currency = body.read_fixstr(3)

			# merchant name
			merchant_name = body.read_varstr()

			# PTA recipient
			recipient = body.read_varstr()

			# ref_data
			ref_data = binascii.hexlify( body.read_varstr() )

			# invoice
			invoice = body.read_varstr()

			# note
			note = body.read_varstr()

			# address of the POS station
			if body.read_bool():
				street = body.read_varstr()
				city = body.read_varstr()
				state = body.read_varstr()
				zipc = body.read_varstr()
				country = body.read_fixstr(2)
				address = '%s, %s, %s %s, %s' % (street, city, state, zipc, country)
			else:
				address = 'not provided'

			# contact info at the place of transaction origination
			if body.read_bool():
				phone = body.read_varstr()
				email = body.read_varstr()
				contact = 'phone: %s, email: %s' % (phone, email)
			else:
				contact = 'not provided'

			# geo-location of the place of transaction origination
			if body.read_bool():
				latitude = body.read_double()
				longitude = body.read_double()
				geolocation = '%s, %s' % (latitude, longitude)
			else:
				geolocation = 'not provided'

			print "--- %s/%s ---\ntx-id: %s\ncounterparty: %s\ntx_time: %s\naddress: %s\ngeolocation: %s\ncontact: %s\ntx_type: %s\ntx_context: %s\namount: %s\ntip: %s\ntax: %s\ncurrency: %s\nmerchant_name: %s\nrecipient: %s\nref-data: %s\ninvoice: %s\nnote: %s\n" % (i, count, tx_id, counterparty, tx_time, address, geolocation, contact, tx_type, tx_context, amount, tip, tax, currency, merchant_name, recipient, ref_data, invoice, note)

		log.info('Returned %s records', count)
예제 #13
0
	def charge(self, payment_bytes):
		#------------------------------------
		#      Payment Authorization Block
		#------------------------------------
		payment_auth_block = pcos.create_output_block( 'Py' )
		payment_auth_block.write_bytes(payment_bytes)

		#------------------------------------
		#      Payment Request Block
		#------------------------------------
		paymnt_req_block = pcos.create_output_block( 'R1' ) 

		# mat
		paymnt_req_block.write_bytestr( binascii.unhexlify( self.args['receiver_mat'] ) )

		# ref data
		paymnt_req_block.write_bytestr( '' )

		# create-time
		paymnt_req_block.write_ulong( long( time.time() + 0.5 ) )

		(charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge']))
		paymnt_req_block.write_long( charge_int ) # value
		paymnt_req_block.write_int( charge_scale ) # scale

		# tax
		paymnt_req_block.write_bool(True) # optional indicator
		(tax_value, tax_scale) = decimal_to_parts(Decimal(self.args['tax']))
		paymnt_req_block.write_long( tax_value ) # value
		paymnt_req_block.write_int( tax_scale ) # scale

		# tip
		paymnt_req_block.write_bool(True) # optional indicator
		(tip_value, tip_scale) = decimal_to_parts(Decimal(self.args['tip']))
		paymnt_req_block.write_long( tip_value ) # value
		paymnt_req_block.write_int( tip_scale ) # scale

		# passcode
		paymnt_req_block.write_string( '1111' )

		# currency
		paymnt_req_block.write_bytes( b"USD" )

		# invoice ID
		paymnt_req_block.write_string( 'inv-123' )

		# note
		paymnt_req_block.write_string( 'happy meal' )

		# no geo-location available
		paymnt_req_block.write_bool(False)

		# list of purchased goods
		paymnt_req_block.write_int(0)

		#------------------------------------
		#      Payment Request Message
		#------------------------------------
		req = pcos.Doc( name="PaymentReq" )
		req.add( payment_auth_block )
		req.add( paymnt_req_block )

		res = self.send( req )
		self.expect_message(res, 'PaymentAck')
예제 #14
0
	def history(self):
		'''Returns transaction history'''

		# page number and page-size
		page_num = int(self.args['page'])
		page_size = int(self.args['size'])

		#------------------------------------
		#      Request Body Block
		#------------------------------------
		out_bo = pcos.create_output_block( 'Bo' )
		# MAT
		out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) )

		# page size and offset
		out_bo.write_uint( page_num )
		out_bo.write_uint( page_size )

		#------------------------------------
		#    History Query Message
		#------------------------------------
		req = pcos.Doc( name="TxnHistoryQuery" )
		req.add( out_bo )

		res = self.send( req )

		assert res.message_id == 'TxnHistoryReply'

		#------------------------------------
		#      Balanace segment
		#------------------------------------
		balance_seg = res.block( 'Bl' )

		rs={}

		#amount
		value = balance_seg.read_long() # value
		scale = balance_seg.read_int() # scale
		balance_amount = value * math.pow(10, scale)

		# read block field(s)
		tm_epoch = balance_seg.read_ulong();
		balance_as_of_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(tm_epoch))

		#------------------------------------
		#   Transaction History segment
		#------------------------------------
		hist_seg = res.block( 'Tr' )

		# total transactions found
		total_count = hist_seg.read_uint()

		# read number of transactions
		count = hist_seg.read_uint()

		for i in xrange(1, count+1):
			print( '-- [ Row %s ] --' % (i+page_num) )
			rs['txn_id'] = hist_seg.read_string()
			rs['device_name'] = hist_seg.read_string()
			rs['txn_as_of_date'] = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(hist_seg.read_ulong()))
			rs['txn_type'] = hist_seg.read_string()
			rs['txn_context'] = hist_seg.read_string()
			rs['currency'] = hist_seg.read_string()

			value = hist_seg.read_long() # value
			scale = hist_seg.read_int() # scale
			rs['txn_amount'] = value * math.pow(10, scale)

			# tax
			if hist_seg.read_bool():
				value = hist_seg.read_long() # value
				scale = hist_seg.read_int() # scale
				rs['txn_tax'] = value * math.pow(10, scale)

			#tip
			if hist_seg.read_bool():
				value = hist_seg.read_long() # value
				scale = hist_seg.read_int() # scale
				rs['txn_tip'] = value * math.pow(10, scale)

			rs['counterparty'] = hist_seg.read_string()
			rs['invoice'] = hist_seg.read_string()
			rs['note'] = hist_seg.read_string()

			# address of the POS station
			if hist_seg.read_bool():
				street = hist_seg.read_string()
				city = hist_seg.read_string()
				state = hist_seg.read_string()
				zipc = hist_seg.read_string()
				country = hist_seg.read_string()
				rs['merchant_address'] = '%s, %s, %s %s, %s' % (street, city, state, zipc, country)

			# contact info
			if hist_seg.read_bool():
				rs['merchant_phone'] = hist_seg.read_string()
				rs['merchant_email'] = hist_seg.read_string()

			# geo location
			if hist_seg.read_bool():
				rs['txn_latitude'] = hist_seg.read_double()
				rs['txn_longitude'] = hist_seg.read_double()

			rs['txn_status'] = hist_seg.read_string()
			
			# rating and score
			rs['user_rating'] = hist_seg.read_uint()
			rs['merchant_score'] = hist_seg.read_double()
 			rs['vote_count'] = hist_seg.read_uint()

			printplus( rs )
			print( '------' )

		page_size = int(self.args['size'])
		log.info('Returned page %s of %s, balance %s as of %s', self.args['page'], int(math.ceil(total_count/page_size)), balance_amount, balance_as_of_date )