Transaction 생성 및 UTXO를 업데이트하는 코드를 작성해보자
코드의 실행 순서는 다음과 같이 진행될 것이다 .
1. 코드 실행 순서
1) Wallet 서버에서 transaction 정보 전송 > axios.post('/sendTransaction')
2) BlockChain 서버의 /sendTransaction에서 sendTransaction() 메서드 실행
3) sendTransaction(\_receivedTx,unspentTxOuts)
3-1) 서명 검증: Wallet.getVerify()
3-2) 발신지갑 최신화 : const myWallet = new this()
3-3) 발신지갑의 잔액과 amount 비교
3-4) transaction 생성
4) 내 계정정보와 일치하는 UTXO 가져오기: getMyUTXO() 생성
5) createTransaction() 메서드 실행
5-1) sum과 txins 생성: createTxIns()
5-2) txouts 생성: createTxOuts()
5-3) new Transaction 생성: const tx = new Transaction(txins,txouts)
5-4) UTXO 업데이트
2. 실행 코드 작성
1-1) req.body 정보 받아서 sendTransaction() 메서드 호출
/* index.ts */
app.post('/sendTransaction', (req, res) => {
try {
const receivedTx: ReceivedTx = req.body;
// post 형식으로 받은 body의 내용과 utxo 배열을 매개변수로 sendTransaction() 메서드 실행
Wallet.sendTransaction(receivedTx, ws.getUnspentTxOuts());
} catch (e) {
if (e instanceof Error) console.error(e.message);
}
res.json([]);
});
2-1) sendTransaction 메서드 () 실행
/* @core/wallet/wallet.ts */
export class Wallet {
//...생략
static sendTransaction(_receivedTx: any, _unspentTxOuts: UnspentTxOut[]): Transaction {
// 1. 서명 검증
const verify = Wallet.getVerify(_receivedTx);
if (verify.isError) throw new Error(verify.error);
// 2. 발신인의 지갑 정보 최신화
const myWallet = new this(_receivedTx.sender, _receivedTx.signature, _unspentTxOuts);
// 3. 최신화된 정보를 가지고 balance 체크
if (myWallet.balance < _receivedTx.amount) throw new Error('금액이 부족합니다');
// 4. transaction을 만드는 과정 - createTransaction() 메서드 생성
const myUTXO = UnspentTxOut.getMyUnspentTxOuts(myWallet.account, _unspentTxOuts);
const tx = Transaction.createTransaction(_receivedTx, myUTXO);
return tx;
}
static getVerify(_receivedTx: ReceivedTx): Failable<undefined, string> {
const { sender, received, amount, signature } = _receivedTx;
const data: [string, string, number] = [sender, received, amount];
const hash: string = SHA256(data.join('')).toString();
const keyPair = ec.keyFromPublic(sender, 'hex');
const isVerify = keyPair.verify(hash, signature);
if (!isVerify) return { isError: true, error: '서명이 올바르지 않습니다' };
return { isError: false, value: undefined };
}
//...생략
}
3) 내 계정과 일치하는 UTXO 가져오기
/* /transaction/unspentTxOut.ts */
export class UnspentTxOut{
//...생략
static getMyUnspentTxOuts(_account: string, _unspentTxOuts: UnspentTxOut[]): UnspentTxOut[] {
//전체 UTXO 중에서 매개변수로 받은 내 계정과 일치하는 UTXO 정보를 필터 메서드로 걸러내기
return _unspentTxOuts.filter((utxo: UnspentTxOut) => utxo.account === _account);
}
}
4) transaction 생성
/* /transaction/transaction.ts */
export class Transaction {
// ...생략
static createTransaction(_receivedTx: any, _myUTXO: UnspentTxOut[]): Transaction {
// 1. txIn을 생성
const { sum, txins } = TxIn.createTxIns(_receivedTx, _myUTXO);
// 2.서명 생성
// 3. txIn 기반으로 txOut 생성
const txouts: TxOut[] = TxOut.createTxOuts(sum, _receivedTx);
// 4. txIn과 txOut 기반으로 new Transaction 생성
const tx = new Transaction(txins, txouts);
return tx;
}
}
4-1) txins 생성
/* /transaction/txin.ts */
export class txIn {
//...생략
static createTxIns(_receivedTx: any, _myUTXO: IUnspentTxOut[]) {
let sum = 0;
let txins: TxIn[] = [];
for (let i = 0; i < _myUTXO.length; i++) {
//myUTXO = [20, 20, 20, 20, 20], amount = 70이라고 가정
const { txOutId, txOutIndex, amount } = _myUTXO[i];
const item: TxIn = new TxIn(txOutId, txOutIndex, _receivedTx.signature);
txins.push(item);
sum += amount;
if (sum >= _receivedTx.amount) return { sum, txins };
}
// 참고, for(const utxo of myUTXO): 같은 문법 for (let i = 0; i < myUTXO.length; i++) {
return { sum, txins };
}
}
4-2) txouts 생성
/* /transaction/txout.tx */
export class TxOut{
//...생략
static createTxOuts(_sum: number, _receivedTx: any): TxOut[] {
const { amount, sender, received } = _receivedTx; //보낼 금액, 보내는사람 '공개키', 받는사람 '계정'
const senderAccount: string = Wallet.getAccount(sender);
const receivedTxOut = new TxOut(received, amount);
const senderTxOut = new TxOut(senderAccount, _sum - amount);
if (senderTxOut.amount <= 0) return [receivedTxOut];
return [receivedTxOut, senderTxOut];
}
}
3. 테스트 코드 작성
import { Chain } from '@core/blockchain/chain';
import { Wallet } from '@core/wallet/wallet';
describe('chain 함수 체크', () => {
let ws: Chain = new Chain(); //[GENESIS]
let receivedTx = {
sender: '02fdfe50d7926f63a76b46e913ee689085e094b4ddf17cc1a3fb9205a90e6a7c78', //발신인의 공개키
received: ' 67b776aa654b0033bac7b47028e17bc02361f28c', //수신인의 계정
amount: 70,
signature: {
r: '2c1e7908ec578df05089fe568551a7f36003bfb3122169c9ec75455bdcbd1c96',
s: '6df02fd7fc3d3f382aac8f72c2f699d37601f7b1e28c42b2da9b493e00e90b8b',
recoveryParam: 1,
},
};
it('addBlock 함수 체크', () => {
// ' 02fdfe50d7926f63a76b46e913ee689085e094b4ddf17cc1a3fb9205a90e6a7c78';
ws.miningBlock('ee689085e094b4ddf17cc1a3fb9205a90e6a7c78');
ws.miningBlock('ee689085e094b4ddf17cc1a3fb9205a90e6a7c78');
ws.miningBlock('ee689085e094b4ddf17cc1a3fb9205a90e6a7c78');
ws.miningBlock('ee689085e094b4ddf17cc1a3fb9205a90e6a7c78');
ws.miningBlock('ee689085e094b4ddf17cc1a3fb9205a90e6a7c78');
});
it('transaction 검증', () => {
try {
const tx = Wallet.sendTransaction(receivedTx, ws.getUnspentTxOuts());
console.log(tx)
} catch (e) {
if (e instanceof Error) console.error(e.message);
}
});
});
4. 테스트 코드 결과
20BTC씩 5번 채굴하여 100BTC를 보유하고 있는 계정에서
70BTC를 산출하는 거래 내역에 대한 테스트 코드 결과이다.
console.log(tx)
// Transaction {
// txIns: [
// TxIn {
// txOutId: '949c07d67ff61c035f3387e09c99e6c473e256741ace844b1ba715ee09395d62',
// txOutIndex: 0,
// signature: [Object]
// },
// TxIn {
// txOutId: '1e70680e2477943cf7594a12ed7a3525c545933df854376165f7db551997b82a',
// txOutIndex: 0,
// signature: [Object]
// },
// TxIn {
// txOutId: '5196bd745609705d9994360759a906e9585f90eb676827eeb5caa71167ff84f8',
// txOutIndex: 0,
// signature: [Object]
// },
// TxIn {
// txOutId: '5ff01642533dc33a26d63c3848a9cdf1bc58f35f72f0b253eb290fbb00d09b42',
// txOutIndex: 0,
// signature: [Object]
// }
// ],
// txOuts: [
// TxOut {
// account: ' 67b776aa654b0033bac7b47028e17bc02361f28c',
// amount: 70
// },
// TxOut {
// account: 'ee689085e094b4ddf17cc1a3fb9205a90e6a7c78',
// amount: 10
// }
// ],
// hash: '8e6195aae6c38fbf00acf7d5838f54656536bc9ccbcfd49bd1ee0ebcea4d8520'
// }
'블록체인' 카테고리의 다른 글
이더리움3. web3 라이브러리 (0) | 2022.06.28 |
---|---|
이더리움 생태계 (0) | 2022.06.27 |
P2P 통신을 통해 노드 간 체인 주고받기[수정중] (0) | 2022.06.20 |
채굴(mining) (0) | 2022.06.20 |
P2P 통신으로 노드 간 블록 주고받기 (0) | 2022.06.14 |
댓글