[Caver] Caver로 Klaytn 계정의 키를 바꾸는 방법 #1 — AccountKeyPublic
전체 포스팅 목록은 여기에서 확인하세요.
🇬🇧:[Caver] How to Update Klaytn Account Keys with Caver #1 AccountKeyPublic
🇫🇷: [Caver] Mettre à jour la clé de compte de Klaytn avec Caver #1 AccountKeyPublic
🇩🇪: [Caver] Klaytn-Kontoschlüssel Updaten mit Caver #1 AccountKeyPublic
- Caver로 Klaytn 계정의 키를 바꾸는 방법 #1 AccountKeyPublic
- Caver로 Klaytn 계정의 키를 바꾸는 방법 #2 AccountKeyWeightedMultiSig
- Caver로 Klaytn 계정의 키를 바꾸는 방법 #3 AccountKeyRoleBased
Klaytn 블록체인의 특별한 점은 키와 주소가 분리되어 있다는 점인데요, 이에 따라 계정에서 사용하는 키를 변경할 수 있습니다. 이 포스팅에서는 caver-js와 caver-java를 사용하여 계정의 키를 AccountKeyPublic으로 변경하는 방법에 대해서 설명합니다. 다양한 AccountKey에 대한 설명은 Klaytn Docs를 참고하세요.
이 문서는 실습 환경을 전제로 설명이 진행됩니다. 실습 환경이 아직 구축되지 않았다면 caver-js — Prerequisites 혹은 caver-java — Prerequisites를 참고하세요.
각 파트에서는 코드의 일부분을 설명하며, 전체 코드는 아래 링크에서 확인할 수 있습니다.
1. Keyring 만들기
먼저 실습에서 사용될 Klaytn 계정을 생성합니다. 이 계정은 트랜잭션을 실제 전송하여 네트워크에 저장된 계정의 키를 업데이트할 계정이기 때문에 충분한 KLAY를 가지고 있어야 합니다.
Caver에서는 Klaytn 계정의 주소와 계정에서 사용하는 private key(s)를 저장하는 구조로서 Keyring을 사용합니다.
먼저 caver-js를 사용하여 Klaytn 계정의 정보를 저장하는 Keyring 인스턴스 생성 방법에 대해서 설명합니다.
// caver-js
const senderKeyring = caver.wallet.keyring.create(senderAddress, senderPrivateKey)
만약 private key string이 아닌 keystore 파일을 가지고 있는 경우, caver.wallet.keyring.decrypt
를 사용하여 keyring을 생성할 수 있습니다.
caver-java를 사용하여 Klaytn 계정의 정보를 저장하는 Keyring 인스턴스 생성 방법은 아래와 같습니다.
// caver-java
SingleKeyring senderKeyring = caver.wallet.keyring.create(senderAddress, senderPrivateKey);
caver-java도 마찬가지로 keystore 파일을 가지고 있는 경우, caver.wallet.keyring.decrypt
를 사용하여 keyring을 생성할 수 있습니다.
2. Caver in-memory wallet에 keyring 추가하기
이 실습에서는 in-memory wallet을 사용합니다. Caver의 in-memory wallet에 keyring이 추가되어 있으면, 트랜잭션에 서명할 때 따로 사용할 키를 지정하지 않아도 in-memory wallet에 저장된 keyring의 키로 서명합니다.
caver-js를 사용하여 in-memory wallet에 keyring을 추가하는 방법은 아래와 같습니다.
// caver-js
caver.wallet.add(senderKeyring)
caver-java도 마찬가지로 아래와 같이 in-memory wallet에 keyring을 추가할 수 있습니다.
// caver-java
caver.wallet.add(senderKeyring);
3. 새로운 개인 키 생성하기
Klaytn 계정의 AccountKey를 AccountKeyPublic으로 업데이트하기 위해서는 Klaytn 계정에서 새롭게 사용할 private key가 필요합니다. 여기서는 generateSingleKey
함수를 통해 랜덤 생성된 private key를 사용합니다. 만약 따로 사용하고자 하는 private key가 있는 경우 이를 사용해도 됩니다.
아래는 caver-js를 사용하여 내 Klaytn 계정에서 사용할 새로운 private key string을 생성하는 방법입니다.
// caver-js
const newKey = caver.wallet.keyring.generateSingleKey()
caver-java도 아래와 같이 generateSingleKey
를 사용하여 내 Klaytn 계정에서 사용할 새로운 private key string을 생성할 수 있습니다.
// caver-java
String newKey = caver.wallet.keyring.generateSingleKey();
4. 새로운 Keyring 생성하기
위에서 Klaytn 계정에서 사용할 새로운 private key를 생성했다면, 이제 새로운 private key를 저장하는 Keyring 인스턴스를 생성해보겠습니다. 새로운 private key를 저장하는 Keyring 인스턴스는 Klaytn 계정의 AccountKey가 성공적으로 변경된 이후에 사용할 수 있습니다.
먼저 caver-js를 사용하여 아래와 같이 새로운 private key를 저장하는 Keyring 인스턴스를 생성할 수 있습니다.
// caver-js
const newKeyring = caver.wallet.keyring.create(senderKeyring.address, newKey)
새 private key를 저장하는 newKeyring
은 newKey
를 사용하여 트랜잭션에 서명합니다.
caver-java를 사용하여 새로운 private key를 저장하는 Keyring 인스턴스 생성 방법은 아래와 같습니다.
// caver-java
SingleKeyring newKeyring = caver.wallet.keyring.create(senderKeyring.getAddress(), newKey);
5. Account 인스턴스 만들기
Caver에서 제공하는 Account 클래스는 계정을 업데이트할 때 필요한 정보를 포함합니다. AccountKeyPublic으로 업데이트하는 경우, 업데이트할 Klaytn 계정의 주소와 새롭게 사용하고자 하는 public key가 필요합니다.
위에서 생성한, 새로운 private key를 저장하고 있는 keyring의 toAccount
함수를 호출하여 Account 인스턴스를 생성할수 있습니다. caver-js로 Account 인스턴스를 생성하는 방법은 아래와 같습니다.
// caver-js
const account = newKeyring.toAccount()
caver-java도 마찬가지로, 새로운 private key를 저장하고 있는 keyring의 `toAccount` 함수를 호출하여 Account 인스턴스를 생성할 수 있습니다.
// caver-java
Account account = newKeyring.toAccount();
이렇게 생성된 Account 인스턴스는 업데이트할 Klaytn 계정의 주소와 새롭게 사용할 private key의 public key를 저장합니다.
6. 트랜잭션 만들기
Account 인스턴스를 생성했다면, 이를 사용하여 Account Update 트랜잭션을 간단하게 생성할 수 있습니다.
먼저 caver-js를 사용하여 트랜잭션을 생성하는 방법은 아래와 같습니다.
// caver-js
const accountUpdate = caver.transaction.accountUpdate.create({
from: senderKeyring.address,
account: account,
gas: 50000,
})
caver-java를 사용하여 트랜잭션을 생성하는 방법은 아래와 같습니다.
// caver-java
AccountUpdate accountUpdate = caver.transaction.accountUpdate.create(
TxPropertyBuilder.accountUpdate()
.setFrom(senderKeyring.getAddress())
.setAccount(account)
.setGas(BigInteger.valueOf(50000))
);
7. 트랜잭션 서명하기
Account Update 트랜잭션을 생성했다면, in-memory wallet에 추가한 keyring을 사용하여 트랜잭션에 서명해야 합니다. Caver에서 제공하는 in-memory wallet인 caver.wallet
에서는 sign
함수를 제공합니다.
먼저 caver-js를 사용하여 트랜잭션을 서명하는 방법은 아래와 같습니다.
// caver-js
await caver.wallet.sign(senderKeyring.address, accountUpdate)
caver-java를 사용하여 트랜잭션에 서명하는 방법은 아래와 같습니다.
// caver-java
caver.wallet.sign(senderKeyring.getAddress(), accountUpdate);
caver.wallet.sign
이 성공적으로 수행되면 accountUpdate
의 signatures
필드에 생성된 서명이 할당된 것을 확인할 수 있습니다.
이제 생성된 트랜잭션을 네트워크로 전송하는 작업만 남아있습니다.
8. 트랜잭션 전송하기
트랜잭션을 생성하고 서명했다면 이를 실제 네트워크에 전송해 봅시다. 이 트랜잭션이 네트워크에서 처리되면 Klaytn 계정의 키가 변경되므로 기존 키는 더이상 사용할 수 없습니다. 그러므로 기존 키를 저장하고 있는 keyring은 사용할 수 없으며, 새로운 private key를 저장하고 있는 새로운 keyring을 사용해야 합니다.
caver.rpc.klay.sendRawTransaction
을 사용하여 서명된 트랜잭션을 네트워크에 전송할 수 있습니다.
아래는 caver-js를 사용하여 트랜잭션을 전송하는 예제로, EventEmitter를 사용합니다.
// caver-js
caver.rpc.klay.sendRawTransaction(accountUpdate)
.on(‘transactionHash’, hash => {
console.log(hash)
})
.on(‘receipt’, receipt => {
console.log(receipt)
})
Caver-js를 사용하여 트랜잭션을 전송할 때, Promise를 사용하여 트랜잭션 처리 결과가 담긴 receipt을 받는 방법은 아래와 같습니다.
// caver-js
const receipt = await caver.rpc.klay.sendRawTransaction(accountUpdate)
아래는 caver-java를 사용하여 트랜잭션을 전송하는 예제입니다.
// caver-java
Bytes32 sendResult = caver.rpc.klay.sendRawTransaction(accountUpdate).send();
String txHash = sendResult.getResult();
위 코드가 실행되면 트랜잭션 해시를 구할 수 있으며, 해당 트랜잭션의 처리 결과는 아래의 방법으로 얻을 수 있습니다.
// caver-javapublic String objectToString(Object value) throws JsonProcessingException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return ow.writeValueAsString(value);
}TransactionReceiptProcessor receiptProcessor = new PollingTransactionReceiptProcessor(caver, 1000, 15);TransactionReceipt.TransactionReceiptData receiptData = receiptProcessor.waitForTransactionReceipt(hash);System.out.println(objectToString(receiptData));
위의 결과로 리턴되는 receipt을 보면 아래와 같이 status가 true로 트랜잭션이 성공적으로 처리된 것을 확인할 수 있습니다. 트랜잭션 타입은 TxTypeAccountUpdate이고 key필드에는 새롭게 업데이트한 AccountKeyPublic이 인코딩된 형태로 리턴되었습니다.
{
blockHash: ‘0x073ae74db35f15c8f763c89ee4cede3f0a9bfb1256d2b28e2e12f2b4c4ccca18’,
blockNumber: ‘0x33c80b0’,
contractAddress: null,
from: ‘0x405e1c9109684626b5b94177335b2db88e974f86’,
gas: ‘0xc350’,
gasPrice: ‘0x5d21dba00’,
gasUsed: ‘0xa028’,
key: ‘0x02a102259cbde6ac40681c0bdb36a7bd714d7f12214f060a3708a964d80a46a8985d94’,
logs: [],
logsBloom: ‘0x00000…’,
nonce: ‘0x0’,
senderTxHash: ‘0x6d0ccf6afb1b715909244fa8d6affdb9a2fcac74f070cffcb10f6cc1b8b0eb8c’,
signatures: [
{ V: ‘0x7f5’, R: ‘0xcc180…’, S: ‘0x161b2…’ }
],
status: ‘0x1’,
transactionHash: ‘0x6d0ccf6afb1b715909244fa8d6affdb9a2fcac74f070cffcb10f6cc1b8b0eb8c’,
transactionIndex: ‘0x0’,
type: ‘TxTypeAccountUpdate’,
typeInt: 32
}
9. AccountKey 확인하기
트랜잭션이 성공적으로 처리되었다면 네트워크에 저장된 계정의 키가 변경됩니다. caver.rpc.klay.getAccountKey
를 사용하여 이를 확인할 수 있습니다.
아래는 caver-js를 사용하여 계정의 accountKey를 확인하는 방법입니다.
// caver-js
const accountKey = await caver.rpc.klay.getAccountKey(senderKeyring.address)
console.log(accountKey)
아래는 caver-java를 사용하여 계정의 accountKey를 확인하는 방법입니다.
// caver-java
AccountKey accountKey = caver.rpc.klay.getAccountKey(senderKeyring.getAddress()).send();
System.out.println(objectToString(accountKey));
위의 결과를 출력하면 아래와 같이 Klaytn 네트워크에 저장된 계정의 키를 알 수 있습니다. 계정의 키를 AccountKeyPublic으로 업데이트했기 때문에 caver.rpc.klay.getAccountKey
결과의 keyType은 2로 출력되는 것을 확인할 수 있습니다. Account Key Type ID에 대한 자세한 내용은 Klaytn Docs를 참고해 주세요.
{
keyType: 2,
key: {
x: ‘0x259cb…’,
y: ‘0x707b7…’
}
}
10. In-memory wallet의 keyring 업데이트
트랜잭션이 성공적으로 처리되어 계정의 키가 업데이트 되었다면, 이제 트랜잭션에 서명할 때 업데이트된 키를 사용해야 합니다.
지금 in-memory wallet에 저장되어 있는, keyring에서 사용하는 키는 업데이트되기 전의 키이므로 트랜잭션을 전송하면 실패하게 됩니다. In-memory wallet의 keyring에서 사용하는 키가 업데이트되지 않은 상태로 트랜잭션을 전송하면 아래와 같은 에러가 발생하게 됩니다.
Error: Returned error: invalid transaction v, r, s values of the sender
그렇기 때문에 Klaytn 계정의 키를 업데이트했다면 in-memory wallet에 별도 저장된 keyring의 키도 업데이트해야 합니다.
caver.wallet.updateKeyring
를 사용하면 in-memory wallet에 저장된, keyring에서 사용하는 private key를 업데이트할 수 있습니다. 업데이트된 Klaytn 계정의 주소와 새로운 private key를 담고있는 newKeyring
은 파라미터 형태로 전송합니다.
아래는 caver-js를 사용해서 in-memory wallet의 keyring을 업데이트하는 방법입니다.
// caver-js
caver.wallet.updateKeyring(newKeyring)
아래는 caver-java를 사용해서 in-memory wallet의 keyring을 업데이트하는 방법입니다.
// caver-java
caver.wallet.updateKeyring(newKeyring);
11. 업데이트된 계정으로 트랜잭션 전송하기
Klaytn 계정의 키가 정상적으로 업데이트되었다면, 이제 업데이트된 계정으로 트랜잭션을 전송해 볼까요?
네트워크에 저장되는 계정의 키가 업데이트되었기 때문에, 트랜잭션을 전송할 때는 업데이트된 키를 사용하여 서명해야 합니다. [10. In-memory wallet의 keyring 업데이트]에서 in-memory wallet에 있는 keyring의 키도 업데이트 했으므로, 트랜잭션을 전송하면 새롭게 업데이트된 키로 서명하여 전송됩니다.
여기서는 간단하게 AccountKey가 업데이트된 Klaytn 계정으로 Value Transfer 트랜잭션을 전송하는 예제에 대해서 설명합니다.
아래에는 caver-js를 사용하여 Value Transfer 트랜잭션을 생성하고 서명하여 전송하는 방법에 대해서 설명합니다.
// caver-js
const vt = caver.transaction.valueTransfer.create({
from: senderKeyring.address,
to: recipientAddress,
value: 1,
gas: 25000,
})await caver.wallet.sign(senderKeyring.address, vt)const vtReceipt = await caver.rpc.klay.sendRawTransaction(vt)
caver.transaction.valueTransfer
로 트랜잭션을 생성한 후, 앞에서 서명한 방식과 동일하게 caver.wallet.sign
함수를 사용하여 트랜잭션에 서명합니다. 이 때 caver.wallet
내부에 저장된 keyring은 [10. In-memory wallet의 keyring 업데이트]에서 업데이트되었으므로 새로운 private key로 트랜잭션에 서명하게 됩니다. 그 이후 서명된 트랜잭션은 caver.rpc.klay.sendRawTransaction
을 사용하여 네트워크로 전송됩니다. 이 예제에서는 Promise를 사용하여 트랜잭션 처리 결과를 받도록 구현되어 있습니다.
그럼 이제 caver-java로 Value Transfer 트랜잭션을 생성하고 서명한 뒤 네트워크에 전송하는 방법에 대해서 설명해볼까요?
// caver-java
ValueTransfer vt = caver.transaction.valueTransfer.create(
TxPropertyBuilder.valueTransfer()
.setFrom(senderKeyring.getAddress())
.setTo(recipientAddress)
.setValue(BigInteger.valueOf(1))
.setGas(BigInteger.valueOf(25000))
);caver.wallet.sign(senderKeyring.getAddress(), vt);Bytes32 vtResult = caver.rpc.klay.sendRawTransaction(vt).send();TransactionReceipt.TransactionReceiptData vtReceiptData = receiptProcessor.waitForTransactionReceipt(vtResult.getResult());
ValueTransfer
트랜잭션을 생성한 후, 앞서 진행한 방식과 동일하게 caver.wallet.sign
함수로 트랜잭션에 서명합니다. 서명된 트랜잭션은 caver.rpc.klay.sendRawTransaction
을 사용하여 네트워크에 전송하고 리턴받은 트랜잭션 해시를 통하여 트랜잭션 처리 결과를 조회합니다.
위의 실습을 통해 계정의 키를 AccountKeyPublic으로 변경하는 방법을 알아보았습니다. 쉽게 이해하셨나요? 다음 포스팅에서는 계정의 키를 AccountKeyWeightedMultiSig으로 변경하는 방법에 대해서 설명해보겠습니다. 새롭게 사용할 키의 종류만 변경될 뿐 과정이 거의 동일하므로 이 문서의 실습을 따라하고 이해하는 데에 문제가 없었다면 다음 포스팅도 쉽게 따라하실 수 있습니다.
포스팅에 사용된 전체 소스코드 링크
궁금한 점은 언제든지 Klaytn 개발자 포럼에 문의해주세요. 😉