728x90

드디어 트랜잭션 호달달 여기부터는 팀플에서 안해본 작업이라서 화이팅,,,해볼게,,

naivecoin 이와 내용같음.

https://newpouy.github.io/jekyll/update/2018/03/22/naivecoin-kr-translate-3.html

 

Naivecoin Korean Translate Version #3

navie코인 번역 원문: lhartikk.github.io

newpouy.github.io

 

트랜잭션 개념

트랜잭션(거래내역)을 써서 우리가 만드는 블록체인이 암호화폐로 쓰일 수 있게 되는거지. 화페를 가졌다는 증거를 보여줄 수 있으면 그걸 보내면서 쓰는거야 이때 필요한 개념은 public-key 암호화, 서명, 트랜잭션인풋 과 아웃풋 등이 있다

 

 

퍼블릭키 암호화와 서명

퍼블릭키 암호화를 위해서는 키 한 쌍 비밀키secret key와 공개키public key가 필요하다. 

공개키는 비밀키로부터 만들어지지만 반대는 불가능! 공개키는 말그대로 public 누구에게나 공유가능

비밀키로 암호메세지를 만들수 있고 그 메세지와 공개키가진 누구나 그 암호메세지가 특정 비밀키로 만들어졌다는 걸 증명할 수 있어. (영지식 증명)

 

퍼블릭 키 암호화하려고 elliptic라이브러리 사용한 다음 두개 암호화함수 쓸거야

 

  • Hash function (SHA256) for 작업 증명과 블록의 고유성 확보
  • Public-key cryptography (ECDSA) for 트랜잭션

유효한 비밀키 private key는 32byte문자열로 이루어진다. (밑에는 예시)

19f128debc1b9122da0635954488b208b829879cf13b3d6cac5d1260c0fd967c

유효한 공개키 public key는 '04'가 붙은 64byte 문자열이다. ->코인을 수신하는 측에서 사용.

04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a

 

 

트랜잭션 

트랜잭션의 아웃풋

transaction outputs (txOut): 코인을 어디로 보낼지에 대한 정보 = 주소와 코인의 양 으로 구성됨

 주소는  ECDSA(타원곡선 디지털서명 알고리즘) 퍼블리키값. 

유저가 특정코인에 접근하기 위해 해당 공개키에 대응하는 private key를 가지고 있어야함

 

class TxOut {

구조

주소 address

양 amount

}

 

 

트랜잭션의 인풋

transaction inputs (txIn): 코인이 어디로부터 왔는지 정보. -오직 비밀키로부터 생성된 서명signature값만 가진다!

각가의 txIn은 이전의 Output을 참조하고 서명 통해 열림. 서명의 역할은 오직 공개키와 한쌍인 비밀키를 가진 사용자만이 트랜잭션을 만들 수 있음을 보증한다. 

class TxIn {

}

 

블록체인은 비밀키 그자체를 가지지 않고 공개키와 서명만을 가진다

 

결과적으로 

트랜잭션 인풋txIn은 코인을 풀고

트랜잭션 아웃풋txOut은 코인을 잠그는 역할을 한다. 

 

트랜잭션 구성(구조)

class Transaction {

(타입스크립트는 안에 타입넣는데 자바스크립트는 안에 아무것도 안넣었음)

}

 

트랜잭션 아이디 Transaction id

트랜잭션 아이디는 트랜잭션 컨텐츠로부터 계산된 해시값이다. 트랜잭션 아이디의 서명은 해시에 포함되지 않지만 

나중에 트랜잭션에 추가될 것임 

//여기 어려워서 map함수랑 reduce함수 개념다시 잡고 왔음

 

트랜잭션 아이디 갖는 함수 

const getTransactionId = (트랜잭션) =>{

txIn컨텐츠 = 트랜잭션.txIns  을 map함수로 (트랙인풋의 txOutId 와  트랙인풋의 txOutIndex)를 계속 더해주고

그리고 reduce로 반복해서 누적값과 현재값을 더해준 것(초기값은 ' ' 빈값)

 

txOut컨텐츠 = 트랜잭션.txOuts 을 map함수로 (트랙아웃풋의 주소 와  트랙아웃풋의 양) 을 계속 더해주고

그리고 reduce로 반복해서 누적값과 현재값을 더해준 것(초기값은 ' ' 빈값)

}

 

여기서 쓴걸로 받아온다고 추정함

 

트랜잭션 서명 

서명된 이후의 트랜잭션 내용이 수정될 수 없다. 트랜잭션이 공개되어서 블록체인에 연결되지 않은 사람도 누구나 그 거래내역에 접근할 수 있어

트랜잭션 인풋에 서명할 때 오직 txId만 서명될거야. 만약에 트랜잭션의 어느 부분이라도 변경되면 txId의 값은 변경되고 이는 해당 트랜잭션과 서명을 무효화한다. 

 

트랜잭션 인풋에 서명하는 함수 

const signTxIn = (트랜잭션, tx인풋인덱스, 비밀키, aUnspentTxOuts) {

 

txIn 은 트랜잭션의 인풋들[인덱스들어간]

dataToSign은 트랜잭션의 아이디

referencedUnspentTxOut는 보내지 않은 트랜잭션아웃풋(인풋의 아웃풋 아이디, 인풋의 아웃풋 인덱스순서, aUnspentTxOuts)을 찾은 것. 

referencedAddress는 참조된보내지지않은 아웃풋의 주소

key는 공개키를 hex로 암호화한 것

signature서명은 암호화

 

서명 뱉어내.

 

누군가가 트랜잭션에 변경을 시도하면 어떻게 되는지 보자

한 노드의 해커가 "코인을 a에서 b주소로 보내" 라고 내용을 가진 거래내용을 txId와 함께 받았다.

해커는 b주소를 c로 바꿔. 수진주소 변경돼서 txId는 더이상 유효하지 않아.

서명 역시 txId기반으로 만들어져서 더 이상 유효하지 않아. 

그래서 변조된 트랜잭션은 다른 노드들에게 받아들여질 수 없다. 

 

 

 

Unspent transaction outputs

보내지지 않은 트랜잭션 아웃풋

 

트랜잭션 인풋은 항상 UtxO 보내지지 않은 트랜잭션 아웃풋을 참조해야해. 

우리가 블롳게인에서 코인을 갖는다는 것은 보내지지 않은 거래아웃풋 목록을 가진다는 것.

이 아웃풋들의 퍼블릭,공개키는 private key 비밀키에 대응한대

트랜잭션 유효성 검증이란 측면에서 이 uTxO보내지지 않은 거래아웃풋은 아주 중요함. 

그리고 이거는 현재 최신상태의 블록체인에서 나와야 되니까 우리는 업데이트를 구현할 거야. 

 

 

보내지지 않은 트랜잭션 아웃풋의 데이터구조

uTxO의 데이터구조

class UnspentTxOut {

트랜잭션 아웃풋 아이디

트랜잭션 아웃풋 인덱스

주소

}

 

보내지지않은 트랜잭션 의 목록의 자료구조는 단순한 배열이다. 

let unspentTxOuts = [] ;

 

 

Updating unspent transaction outputs

새로운 블록이 더해질때마다 uTxO 보내지지않은 트랜잭션업데이트해야한다. 

새로운 트랜잭션(거래내역)은 기존의 트랜잭션 아웃풋 목록에 영향을 주고 새로운 아웃풋을 발생시키기 때문이다.

이를 위해 새로 생성된 블록으로부터 '새로운 보내지지않은 트랜잭션 아웃풋들'을 순회하는 돌아다니면서 찾아보는 작업을 할거야. 

 

새로운보내지지않는 트랜잭션 아웃풋들 함수

const newUnspentTxOuts = 

새로운 트랜잭션에서 하나씩 작업할거야

(그배열의 트랜잭션아웃풋목록들에서 아웃풋, 인덱스를 내보낼거야

아이디랑, 인덱스랑, 아웃풋의 주소, 아웃풋의 양을

새로운 보내지지 않은아웃풋에 넣어서..)

 

그리고 그걸 누적값의 배열에 현재값을 더한 값.

 

 

 

블록에서 이미 소비된 트랜잭션 아웃풋들에 대해서도 알아야함. 

새 트랜잭션의 인풋을 검사하면 알수 있다!

 

소비된트랜잭션아웃풋들 함수

const consumedTxOuts = 

새 트랜잭션에서 돌면서 인풋들 찾아내

찾아낸 누적값에 현재값을 더해. (누적값의 초기값은 빈[]배열임)

그리고 그걸(트랜잭션인풋) 새로운 보내지지 않은 트랜잭션아웃풋으로 보내는데

보낼때 (트랜잭션인풋의 아웃풋 아이디, 트랜잭션인풋의 아웃풋 인덱스, ' ', 0) 을 담아서 

배열로 내보내????

 

//어렵다..ㅠㅠㅠ

 

이미 소비된 아웃풋을 제거하고 이제 새로운 트랜잭션 아웃풋을 만들 수 있게됨

 

결과적으로(?)보내지지않은트랜잭션아웃풋들 함수

const resultingUnspentTxOuts =

보내지않은 트랜잭션 아웃풋에 

필터 거쳐라 

findUnspentTxOut(보내지지않은tx아웃풋의 아웃풋아이디, uTxO의 아웃풋인덱스, 소비된 아웃풋)가 아닌 것!

그리고 거기에 새로운보내지않은트랙잰션아웃풋들 넣어라 

 

 

 undateUnspentTxOuts함수가 이 작업들을 총괄 수행할거임. 

그리고 이함수는 반드시 트랜잭션의 유효성이 검증된 이후에 수행되어야한다.

 

 

Transactions validation 트랜잭션 유효성 검증

이제 마침내 무엇이 트랜잭션을 유효하게 만드는지 모습을 잡을 수 있게 되었음

Correct tracnsaction structure 정확한 트랜잭션 구성

트랜잭션은 정의된 방식을 따라야만 한다. 

 

트랜잭션구조가 맞는지 보는 함수

const isValidTransactionStructure =(트랜잭션) =>{

만약에

트랜잭션의 아이디가 문자열string이 아니면

트랜잭션아이디를 찾을 수 없다고 뜨게 하고

틀림 내보내

...

}

 

Valid transaction 유효한 트랜잭션 아이디

ID 확인해야함 

if (트랜잭션아이디가져왔을 때 == 트랜잭션 아이디 가 아니면 ) {

유효한 아이디아니라고 뜨고 

틀림 내보내

}

 

Valid txIns

트랜잭션 인풋들의 서명도 사용되지 않은 아웃풋을 잘 참조하고 있는지 확인해야함 

const validateTxIn = (트랜잭션인풋, 트랜잭션, a안보내진트랜잭션아웃풋) {

만약에 참조된트랜잭션 아웃풋이 없을 때 null일때 {

참조된 트랜잭션 아웃풋 찾을 수 없다고 띄우고 + 트랜잭션 인풋을 JSON형태로 문자로 보여

그리고 틀림 내보내

}

 

주소는 = 언급된 트랜잭션아웃풋의 주소

키는 = 주소를 hex화한거(?)

return key.verify(transaction.id, txIn.signature);

}

 

Valid txOut values

유효한 아웃풋 값인지 확인!

아웃풋의 코인개수와 인풋의 코인갯수도 같아야만한다. 아웃풋이 50개면 인풋도 50개!

 

전체 트랜잭션인풋의 값들

const totalTxInValues = 

트랜잭션의 인풋들

을 맵함수로 하나씩 작업하는데

(인풋들을 getTxInAmount로 )

그걸 초기값 0부터 시작해서 누적값과 현재값 더해줘

 

전체 트랜잭션아웃풋들의 값들 

const totalTxOutValues = 

트랜잭션의 아웃풋들

을 맵함수로 하나씩 트랜잭션 아웃풋 수량꺼내고

그걸 초기값 0부터 시작해서 누적값과 현재값 더해줘

 

만약에 (전체 트랜잭션아웃풋들의 값이 전체 트랜젝션잇풋값과 다르면) {

전체 트렌잭션아웃풋 값들이  트렌잭션 안에 있는 전체 인풋값들과 다르다! 

띄우고 

트랜잭션 아이디 보여주고

틀림 내보냄

}

 

Coinbase transaction

트랜잭션 인풋은 항상 

보내지지않은 트랜잭션 아웃풋들 unspent transaction outputs을 참조해야해!

 

하지만 최초의 코인은 어디를 참조해야하지?

이를 해결하기 위해 coinbase transaction이 필요해! 

코인베이스 트랜잭션은 오직 아웃풋만 포함해. 인풋은 없어.

코인베이스 트랜잭션이 새로운 코인을 돌게 만드는 펌프같은 역할을 할거야. (나는 거래하기 위해서 기존에 넣어둔, 채굴자한테 줄 꽁돈이라고 이해했어.. 내보내기 위해 준비된 양)

코인베이스 아웃풋의 양을 50코인으로 정했어

 

const COINBASE_AMOUNT = 50;

 

코인베이스 트랜잭션은 당연히 노드의 첫 트랜잭션이고

블록 채굴자정보를 포함해. 블록을 발견한 댓가로 채굴자는 첫 코인베이스 트랜잭션 아웃풋으로 코인 50개를 받을거야.

 

코인베이스 트랜잭션의 인풋에는 block의 height값을 넣을게. (코인베이스 트랜잭션에 인풋없다며! ) 여기서 인풋 안에 넣은 블록의 height높이 값이 고유한 ID값 역할한대. 이 고유값이 없으면 코인베이스 트랜잭션은 항상 같은 주소에 50코인을 발행하게 돼

(트랜잭션 인풋은 코인이 어디로부터 왔는지에 대한 정보제공하는 것. 코인을 풀고 코인을 잠그는 역할함.. )

 

 

코인베이스 트랜잭션의 유효성 검증 (은 다른 트랜잭션이랑 좀 다를거야)

const validateCoinbaseTx = (트랜잭션, 블록인덱스) =>{

만약에 트랜잭션 아이디가져온게 !== 트랜잭션 아이디와 달라

유효하지 않은 코인베이스 트랜잭션 아이디야~

틀림뱉음

 

만약에  트랜잭션의 인풋들의 길이가 1이 아니면 

(//빈 문자열은 length가 0이래)

'하나의 txIn은 코인베이스 트랜잭션에 지정되어야한다' 라고 뜸

 

만약에 트랜잭션의 인풋들의 0번째 배열의 트랜잭션아웃풋인덱스가 

블록인덱스가 아니면 

'코인베이스 트랜잭션 안에 있는 그 트랜잭션 인풋의 인덱스는 반드시 그 블록의 높이가 되어야한다.'

틀림 뱉음

 

만약에 트랜잭션의 트랜잭션아웃풋들의 길이가 1이 아니면

코인베이스 트랜잭션안에 있는 트랜잭션 아웃풋들이 유효하지않은 숫자다

틀림뱉음

 

만약에 트랜잭션의 아웃풋들의 0번째배열의 양이 

코인베이스 양과 다르면

'코인베이스 거래내역에서 유효하지 않은 코인베이스 양'

틀림뱉음

 

 

다 맞으면 통과~

}

 

 

 

결론

이 챕터에서 우리는 블록체인의 트랜잭션 거래내역에 대해 알아봤어요

트랜잭션, 거래내역은

인풋과 아웃풋으로 

구성되어있다는 것. 

 

 

기본개념은 간단해.

사용되지 않은 트랜잭션 아웃풋과 블록체인의 잠금해제된 부분이 유효하다는 걸 보여줄거야. 

 

하지만 트랜잭션을 실제로 만드는건 어렵쥐..

인풋과 아웃풋 만들고

프라이빗 키를 사용해서 그들에 서명해야해

이 과정은 다음챕터의 지갑wallet을 배우면 달라질거야

 

아직 연결된 트랜잭션에 대해서도 안살펴봤어.

블록체인이 트랜잭션 거래를 일으키기 위해서는 채굴을 해야만 해.

이때 '트랜잭션 fee'라는 개념도 필요해 다음챕터에서 볼거임

 

 

+

여기까지해본 코드로 해봤는데

map함수로 읽을수 없다고..

코드 확인해보니까 같은뎀..

근데 여기까지 나와있는 코드로 돌려봐도 작동안된다!

챕터4까지 해보고 돌려보자~~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

+ Recent posts