블록체인/IOTA

In depth explanation of how IOTA making a transaction

KimLinear 2018. 3. 8. 22:07

원문 출처:  https://medium.com/biilabs/in-depth-explanation-of-how-iota-making-a-transaction-bcdd9713b939


이 글은 IOTA에서 Transaction이 어떻게 생성되는지에 대한 설명을 담은 원문을 한글로 번역한 것 입니다. 오역이 있을 수 있으니 원문과 비교하여 읽으면 도움이 될 것 같습니다.



In depth explanation of how IOTA making a transaction




이 게시물은 IOTA가 트랜잭션에서 번들로, 해시에서 주소로, 개인 키에서 서명 메시지로 트랜잭션을 만드는 방법을 자세히 설명합니다. 이것은 IOTA가 한 주소에서 다른 주소로 거래를 제안하는 방법을 알기 위해 필요한 전부입니다.


0. Before We Start


이 두 가지 자료를 이미 읽었는지 확인하십시오. 당신에게 IOTA 거래의 기본 견해를 제공합니다.

  1. 1. Bundles — IOTA Documentations (https://iota.readme.io/v1.2.0/docs/bundles)
IOTA는 계정과 같은 체계를 사용합니다. 즉, 토큰을 전송하기 위해 지출해야하는 입력 사항 (주소)이 있음을 의미합니다. 주소는 개인 키에서 생성되며, 개인 키는 다시 try-encoded 시드에서 파생됩니다. IOTA에서의 Transfer(전송)은 산출물과 투입물로 구성된 번들입니다. 번들은 원자 전송(atomic transfers) 방식으로, 번들 내부의 모든 트랜잭션이 네트워크에 의해 받아 들여 지거나 전혀 사용되지 않습니다. IOTA의 일반적인 전송은 4 개의 트랜잭션으로 구성된 번들입니다.

     index

    Purpose 

    Value

    0

    Output . 거래 수령자 (Recipient of the transaction)

     > 0 (as defined by user)

    1

     주소 입력 전체를 소비하는 첫 x 째 번들 항목.  또한 이 번들 항목은 서명의 첫번째 부분을 포함합니다 (이 경우에는 Alice의 서명의 전반부가 됩니다)

     < 0 (spending of input)

    2

     Alice의 서명의 후반부 

    0

     Output . 나머지가있는 경우 (Alice가 각 키 인덱스에서 전체 잔액을 지출하지 않은 경우) 나머지 주소로 전송됩니다.

     > 0 (Input - output)


번들의 고유 한 기능은 트랜잭션이 번들 해시 뿐만 아니라 trunkTransaction을 통해서도 식별된다는 것입니다. 즉, Tail transaction(currentIndex : 0)은 trunkTransaction에서 트랜잭션 해시를 인덱스 1에서 참조하고, currentIndex 1 트랜잭션은 인덱스 2를 참조 (및 승인)합니다. 이렇게 하면 trunkTransaction을 순회하여 꼬리 트랜잭션에서 트랜잭션 번들 전체를 얻을 수 있습니다. 

단일 트랜잭션에는 분명히 여러 입력 및 출력이 포함될 수 있습니다.
  1. 2. Making a Transaction — IOTA Documentations (https://iota.readme.io/v1.2.0/docs/making-a-transaction)

앞서 언급했듯이 IOTA에는 채굴자(Miner)가 없습니다. 이와 같이 트랜잭션을 만드는 프로세스는 오늘날 블록 체인과 다릅니다. IOTA의 절차는 다음과 같습니다.

1. Signing: 개인 키를 사용하여 거래 입력에 서명합니다. 이 작업은 오프라인으로 수행 할 수 있습니다.

2. Tip Selection: MCMC는 트랜잭션 (branchTransaction 및 trunkTransaction)에서 참조 할 두 가지 팁을 무작위로 선택하는 데 사용됩니다.

3. Proof of Work: 네트워크에서 거래를 승인 받으려면 Bitcoin (스팸 및 sybil-resistance)이 아닌 Hashcash와 유사한 일부 작업 증명을 수행해야합니다. 이것은 보통 현대 PC에 몇 분이 소요됩니다.

이 작업이 완료되면 트랜잭션 객체의 trunkTransaction, branchTransaction 및 nonce가 업데이트되어야합니다. 즉, 거래를 네트워크에 지금 브로드 캐스트하고 다른 사람이 거래를 승인 할 때까지 기다릴 수 있습니다. 

1. The Steps to make a transaction



번들 만들기에는 모든 입력과 출력이 포함됩니다.

1. 출력 트랜잭션 준비

2. 입력 값이 출력 값을 만족할 때까지 입력 트랜잭션을 준비합니다.

3. Bundle hash를 얻고 모든 트랜잭션에 채우기 위해 최종 묶음

4. 서명 메시지 조각 작성에 대한 트랜잭션 처리

트렁크(trunk) 및 분기 해시(Branch hash)에 대한 두 가지 tip 얻기 

IRI getTransactionsToApprove를 통해


Proof of Work

1. 트랜잭션에 trunk branch hash 채우기

2. 태그가 설정되지 않은 경우 obsolete tag(오래된 태그)로 태그를 채우기.

3. 트랜잭션에 Timestamp 채우기

4. pearlDiver를 통해 nonce를 계산하고 Transaction hash를 얻습니다.

2. Making bundle


IOTA 번들에는 3 가지 유형의 트랜잭션이 포함되어 있습니다. Input transaction(입력 트랜잭션), Output transaction(출력 트랜잭션), and Meta transaction(메타 트랜잭션).

Input transaction: Transaction value가 음수
Output transaction: Transcation value가 양수.
Meta transaction: Transaction value 가 0, 그것은 서명의 carieer가 될 수 있거나 트랜잭션의 siganture 메시지 조각에 다른 메시지를 저장할 수 있습니다.


예를 들어 봅시다. A는 동일한 시드로부터 3 개의 주소를 가지며 몇개의 value를 가집니다.


Gather all transaction we need in bundle


- index 0: AAAAAAAA, balance: 50

- index 1: BBBBBBBB, balance: 70

- index 2: CCCCCCCC, balance: 20


A가 B의 주소 DDDDDDDD로 100i를 보낼 때, IOTA는 다음과 같이 할 것입니다 :


번들로 필요한 모든 거래를 모으기


B의 주소로 Output Transaction 준비 및 Bundle에 추가

Balance와 함께 A의 주소에서 Input Transaction 준비

Meta Transaction 슬롯을 사용하여 각각의 Input Transaction을 Bundle에 추가한다. 


메타 트랜잭션 슬롯 금액은 주소 보안 수준에 따라 다르며 주소의 기본 보안 수준은 2입니다. 즉, 트랜잭션 서명을 전달하는 데 하나의 추가 트랜잭션이 필요합니다.


번들의 잔액이 여전히 양수인 경우 사용되지 않은 출력 트랜잭션을 추가하여 소비되지 않은 값(Unspent value)을 이동합니다


Bundle finalized


 번들 Balance가 0인지 체크(입력 값 = 출력 값, Kirchhoff의 회선 법칙(Kirchhoff’s circuit laws)을 recall)



Generate bundle hash


- Kerl을 사용하여 transaction 유효성 검사 항목(address, value, obsolete tag, timestamp, current index, and last index)으로 흡수한다.


- Bundle trit을 집어 내고 Bundle hash로 변환한다.

- Secure bundle hash 생성 여부를 확인하고, 그렇지 않으면 obsolete tag(폐기 태그)를 증가시키고 다시 생성한다. (https://github.com/iotaledger/iota.lib.py/issues/84)


- 모든 트랜잭션에 Bundle hash 및 초기화 서명 조각을 채워넣는다 


- transaction hash, transaction tips, signature fragment and nonce가 이 단계에서 채워있지 않음을 확인하고 bundle hash만 결정됩니다.



Bundle signing


- seed를 통해 키 생성기(key generator) 가져 오기


- 트랜잭션을 반복하고 만약 트랜잭션이 Output transaction이면 이 transaction을 signing하려고 시도할 것이다(만약 필요하면 meta transaction으로). 


- 주소 index 및 security level으로 키 생성을 통해 Address private key를 얻는다.


- address private key와 bundle hash를 사용하여 signature fragment(서명 조각)을 생성하고 트랜잭션의 signature fragment 부분을 채 운다.


- 만약 security level이 2인 경우 2개의 transaction에 사인을 해야 한다. (output transaction과 다음 meta transaction인 경우 1개)



이 단계가 끝나면, bundle hash 및 transaction signature를 역순으로 (마지막 index부터 0 index 까지) transaction trytes들의 리스트를 얻는다.




3. Get two tips for trunk and branch


이 글에서 나는 MCMC 알고리즘을 다루지 않을 것이며, 이것을 블랙 박스라고 생각한다. getTransactionsToApprove를 통해 IRI로부터 두 가지 팁을 얻을 수있다.




4. Proof of Work


마지막 단계에서는 번들의 각 트랜잭션에 trunk, branch 및 nonce (여기에서 작업 증명!)를 채워야한다.


번들 설명서에 언급된 바와 같이, 번들은 Tangle 안의 Atomic transfer(원자적 전송) 항목이다. 즉, 하나의 bundle 안에서 같은 팁들을 가지고 있어야 한다.



그런 다음 Bundle의 모든 트랜잭션을 마지막 인덱스부터 0 인덱스까지 trunk, branch hash, time stamp을 채우기 위해 이동하고 nonce값을 찾ㄱ고 transaction hash를 생성하기 위한 PoW를 수행하고 PoW 결과의 유효성을 검사한다.


마지막 인덱스의 트랜잭션 트렁크와 분기 해시는 우리가 얻는 이전 팁이 될 것이다. 다른 트랜잭션의 트렁크는 이전 트랜잭션의 해시이고 분기 해시는 팁의 트렁크 트랜잭션이다. 



모든 것이 제대로 되었으면 모든 필드가 채워진 전체 트랜잭션 trytes를 얻을 수 있습니다!



5. PoC code for Python with PyOTA



# -*- coding: utf-8 -*-
# This is a POC code to generate IOTA transaction and bundle
#
# Note: You will need to implement getTransactionsToApprove
#
import iota
import pearldiver
SEED = 'GENERATE_YORU_SELF'
tag = iota.Tag('TESTINGPYTHON')
pt = iota.ProposedTransaction(
address=iota.Address('9TPHVCFLAZTZSDUWFBLCJOZICJKKPVDMAASWJZNFFBKRDDTEOUJHR9JVGTJNI9IYNVISZVXARWJFKUZWC'),
value=90,
tag=tag,
message=iota.TryteString('HELLO')
)
pb = iota.ProposedBundle([pt])
# pb.add_inputs([list])
# pb._create_input_transaction(addy)
addy = iota.Address('INDTKDAH9GGWDAJDWQLWUKCIHSYNEFQUGVHOYWLZRYPEZIZYQHQJNDLDPCLWMMO9UAEZUWPHMWZRLWGOB')
addy.balance = 100
addy.key_index = 2
addy.security_level = 2
inputs = [
iota.ProposedTransaction(
address=addy,
tag=tag,
value=-addy.balance
)
]
for input in inputs:
pb._transactions.append(input)
for _ in range(addy.security_level - 1):
pb._transactions.append(iota.ProposedTransaction(
address=addy,
tag=tag,
value=0
))
# send unspent inputs to
unspent = iota.Address('HWFZCLVY9RPTAWC9OIOSHXSWFIYMSYSYBHZER9BYZ9KUPUJTRUOLKSGISILWFCWJO9LNZOLWRCJMVDJGD')
pb.send_unspent_inputs_to(unspent)
# This will get the bundle hash
pb.finalize()
# If the transaction need sign, it will then sign-up the transaction
# to fill up signature fragements
kg = iota.crypto.signing.KeyGenerator(SEED)
# pb.sign_inputs(kg)
i = 0
while i < len(pb):
txn = pb[i]
if txn.value < 0:
if txn.address.key_index is None or txn.address.security_level is None:
raise ValueError
# pb.sign_input_at(i, kg.get_key_for(txn.address))
address_priv_key = kg.get_key_for(txn.address)
# Fill in signature fragement
# address_priv_key.sign_input_transactions(pb, i)
from iota.crypto.signing import SignatureFragmentGenerator
sfg = SignatureFragmentGenerator(address_priv_key, pb.hash)
for j in range(address_priv_key.security_level):
txn = pb[i + j]
txn.signature_message_fragment = next(sfg)
i += txn.address.security_level
else:
i += 1
# Now each transaction have their signature into bundle
# this is the end of the transaction construction.
# We can now propose the transaction to tangle
# At this moment, tips still not inside each transaction,
# and each transaction hash is not yet generated
trytes = pb.as_tryte_strings()
# Get tips by getTransactionsToApprove
# tips = getTransactionsToApprove()
trunk_hash = iota.Hash('')
branch_hash = iota.Hash('')
# Do PoW (attach to tangle)
prev_tx = None
for tx_tryte in trytes:
txn = iota.Transaction.from_tryte_string(tx_tryte)
txn.trunk_transaction_hash = trunk_hash if prev_tx is None else prev_tx.hash
txn.branch_transaction_hash = branch_hash if prev_tx is None else trunk_hash
# Copy obsolete tag if tag field is empty
if not txn.tag:
txn.tag = txn.obsolete_tag
# Copy timestamp
txn.timestamp = None
txn.timestamp_lower_bound = None
txn.timestamp_upper_bound = None
# Do the PoW for this transaction
diver = pearldiver.PearlDiver()
trits = txn.trits()
diver.search(trits, min_weight_magniude, -1)
# Validate PoW
# transactionValidator.validate(txn.as_trits())


6. Conclusion


여기서는 IOTA가 트랜잭션을 사용하여 Bundle을 구성하는 방법과 bundle hash, transaction hash, trunk hash, branch hash 및 nonce.와 같은 트랜잭션의 중요한 부분을 채울 때에 대해 설명한다.


우리는 명확하게 알고있다 트랜잭션을 생성하는 모든 단계에서 IoT 디바이스의 핵심 부분은 본인의 Transaction에 Signing하는 부분만 신경쓰고 나머지 other output transaction, tip selection and PoW 는 해당 디바이스에서 수행될 필요가 없다.