class Laksa::Account::Transaction

Transaction

Transaction is a functor. Its purpose is to encode the possible states a Transaction can be in: Confirmed, Rejected, Pending, or Initialised (i.e., not broadcasted).

Constants

GET_TX_ATTEMPTS

Attributes

amount[RW]
code[RW]
data[RW]
gas_limit[RW]
gas_price[RW]
id[RW]
nonce[RW]
provider[RW]
receipt[RW]
sender_pub_key[RW]
signature[RW]
status[RW]
to_addr[RW]
to_ds[RW]
version[RW]

Public Class Methods

confirm(tx_params, provider) click to toggle source

constructs an already-confirmed transaction.

# File lib/laksa/account/transaction.rb, line 35
def self.confirm(tx_params, provider)
  Transaction.new(tx_params, provider, TxStatus::CONFIRMED)
end
new(tx_params, provider, status = TxStatus::INITIALIZED, to_ds = false) click to toggle source
# File lib/laksa/account/transaction.rb, line 14
def initialize(tx_params, provider, status = TxStatus::INITIALIZED, to_ds = false)
  if tx_params
    @version = tx_params.version;
    @nonce = tx_params.nonce
    @amount = tx_params.amount
    @gas_price = tx_params.gas_price
    @gas_limit = tx_params.gas_limit
    @signature = tx_params.signature
    @receipt = tx_params.receipt
    @sender_pub_key = tx_params.sender_pub_key
    @to_addr = tx_params.to_addr.downcase
    @code = tx_params.code
    @data = tx_params.data
  end

  @provider = provider
  @status = status
  @to_ds = to_ds
end
reject(tx_params, provider) click to toggle source

constructs an already-rejected transaction.

# File lib/laksa/account/transaction.rb, line 40
def self.reject(tx_params, provider) 
  Transaction.new(tx_params, provider, TxStatus::REJECTED)
end

Public Instance Methods

bytes() click to toggle source
# File lib/laksa/account/transaction.rb, line 44
def bytes
  protocol = Laksa::Proto::ProtoTransactionCoreInfo.new
  protocol.version = self.version
  protocol.nonce = self.nonce
  protocol.toaddr =  Util.decode_hex(self.to_addr.downcase.sub('0x',''))
  protocol.senderpubkey = Laksa::Proto::ByteArray.new(data: Util.decode_hex(self.sender_pub_key))

  raise 'standard length exceeded for value' if self.amount.to_i > 2 ** 128 - 1

  protocol.amount = Laksa::Proto::ByteArray.new(data: bigint_to_bytes(self.amount.to_i))
  protocol.gasprice = Laksa::Proto::ByteArray.new(data: bigint_to_bytes(self.gas_price.to_i))
  protocol.gaslimit = self.gas_limit
  protocol.code = self.code if self.code
  protocol.data = self.data if self.data

  Laksa::Proto::ProtoTransactionCoreInfo.encode(protocol)
end
confirm(tx_hash, max_attempts = GET_TX_ATTEMPTS, interval = 1) click to toggle source

This sets the Transaction instance to a state of pending. Calling this function kicks off a passive loop that polls the lookup node for confirmation on the txHash.

The polls are performed with a linear backoff:

This is a low-level method that you should generally not have to use directly.

# File lib/laksa/account/transaction.rb, line 120
def confirm(tx_hash, max_attempts = GET_TX_ATTEMPTS, interval = 1)
  @status = TxStatus::PENDING
  1.upto(max_attempts) do 
    if self.track_tx(tx_hash)
      return self
    else
      sleep(interval)
    end
  end

  self.status = TxStatus::REJECTED
  throw 'The transaction is still not confirmed after ${maxAttempts} attempts.'
end
confirmed?() click to toggle source
# File lib/laksa/account/transaction.rb, line 104
def confirmed?
  @status === TxStatus::CONFIRMED;
end
initialised?() click to toggle source
# File lib/laksa/account/transaction.rb, line 100
def initialised?
  @status === TxStatus::INITIALIZED
end
pending?() click to toggle source
# File lib/laksa/account/transaction.rb, line 96
def pending?
  @status == TxStatus::PENDING
end
rejected?() click to toggle source
# File lib/laksa/account/transaction.rb, line 108
def rejected?
  @status === TxStatus::REJECTED;
end
to_payload() click to toggle source
# File lib/laksa/account/transaction.rb, line 81
def to_payload
  {
    version: self.version.to_i,
    nonce: self.nonce.to_i,
    toAddr: Wallet.to_checksum_address(self.to_addr),
    amount: self.amount,
    pubKey: self.sender_pub_key,
    gasPrice: self.gas_price,
    gasLimit: self.gas_limit,
    code: self.code,
    data: self.data,
    signature: self.signature
  }
end
track_tx(tx_hash) click to toggle source
# File lib/laksa/account/transaction.rb, line 134
def track_tx(tx_hash) 
  puts "tracking transaction: #{tx_hash}"

  begin
    response = @provider.GetTransaction(tx_hash)
  rescue Exception => e
    puts "transaction not confirmed yet"
    puts e
  end

  if response['error']
    puts "transaction not confirmed yet"
    return false;
  end

  self.id = response['result']['ID']
  self.receipt = response['result']['receipt']
  self.receipt['cumulative_gas'] = response['result']['receipt']['cumulative_gas'].to_i

  if self.receipt && self.receipt['success']
    puts "Transaction confirmed!"
    self.status = TxStatus::CONFIRMED
  else
    puts "Transaction rejected!"
    self.status = TxStatus::REJECTED
  end

  true
end
tx_params() click to toggle source
# File lib/laksa/account/transaction.rb, line 62
def tx_params
  tx_params = TxParams.new

  tx_params.id = self.id
  tx_params.version = self.version
  tx_params.nonce = self.nonce
  tx_params.amount = self.amount
  tx_params.gas_price = self.gas_price
  tx_params.gas_limit = self.gas_limit
  tx_params.signature = self.signature
  tx_params.receipt = self.receipt
  tx_params.sender_pub_key = self.sender_pub_key
  tx_params.to_addr = Wallet.to_checksum_address(self.to_addr)
  tx_params.code = self.code
  tx_params.data = self.data

  tx_params
end

Private Instance Methods

bigint_to_bytes(value) click to toggle source
# File lib/laksa/account/transaction.rb, line 165
def bigint_to_bytes(value)
  raise 'standard length exceeded for value' if value > 2 ** 128 - 1
  bs = [value / (2 ** 64), value % (2 ** 64)].pack('Q>*')
end