이번 caver-java 1.5.0 버전은 Common Architecture를 도입했습니다. Common Architecture란 Klaytn 개발 환경을 위한 새로운 소프트웨어 아키텍처로써 모든 Klaytn SDKs (caver-js/caver-java)가 공유합니다. Common Architecture는 여러분이 더 간편하고 더 체계적으로 개발하며 다른 프로그래밍 언어로 더 쉽게 확장하도록 설계되었습니다.
caver-java가 1.5.0으로 업데이트되면서 일부 API를 제외한 1.4.0 API는 이제 사용되지 않습니다.
caver-java 1.5.0이 새롭게 제공하는 API는 아래와 같습니다.
caver.account
caver.account는 Klaytn 계정의 AccountKey를 업데이트하기 위한 패키지입니다. AccountKey는 1개 이상의 공개키(AccountKeyPublic, AccountKeyWeightedMultiSig, AccountKeyRoleBased) 또는 특수 타입 키(AccountKeyLegacy, AccountKeyFail)입니다.
caver.wallet은 인메모리 지갑에서 Keyring 인스턴스를 관리하도록 하는 패키지입니다. Keyring이란 어떤 Klaytn 계정 주소와 그 주소의 개인키(들)를 저장하는 인스턴스입니다. 키링은 이 계정 주소가 트랜잭션에 서명할 때 사용됩니다. caver.wallet은 모든 종류의 Keyring (SingleKeyring, MultipleKeyring, RoleBasedKeyring)을 수용하며 각 Klaytn 계정 주소를 가지고 이를 관리합니다.
caver.rpc.klay와 caver.rpc.net은 caver-java 1.4.0의 Klay, Net 인터페이스를 각각 대체합니다.
caver.util
caver.utils는 유틸리티 함수를 제공합니다.
caver.contract
caver.contract 패키지를 사용하면 Klaytn의 스마트 컨트랙트를 쉽게 다룰 수 있습니다. caver.contract로 스마트 컨트랙트를 배포하고 스마트 컨트랙트 함수를 호출해 실행할 수 있습니다. caver.contract는 먼저 스마트 컨트랙트 함수와 이벤트들을 ABI(Application Binary Interface)에서 변환하여 함수를 호출하고 이벤트 정보를 얻습니다.
준비 사항
저장소 추가
IPFS를 사용하기 전 라이브러리 저장소가 추가되어야 합니다. 우선 아래 저장소를 추가합니다.
안드로이드 의존성을 사용하려면, 버전 문자열 끝에 -android를 추가하세요. (가령 1.0.1-android)
JSON-RPC 요청 및 응답에 대한 세부 사항을 보려면, LOGBack 의존성을 프로젝트에 포함하세요. 아래는 Gradle 빌드 파일 예제입니다. Maven에도 의존성을 추가할 수 있습니다. caver-java가 SLF4J 로깅 퍼사드(logging facade)를 사용하기 때문에, LOGBack 대신 선호하는 로깅 프레임워크로 전환할 수 있습니다.
이 장은 keystore file을 사용해 KLAY를 전송하는 간단한 KLAY 전송 트랜잭션 예시를 설명합니다. 키스토어 파일은 Klaytn Wallet에 생성될 수 있습니다. 테스트를 위해 KLAY가 필요한 경우 Klaytn Wallet에서 Baobab testnet KLAY를 얻을 수 있습니다.
publicvoidsendingKLAY() throws IOException, CipherException, TransactionException {Caver caver =newCaver(Caver.BAOBAB_URL);//keystore json 파일을 읽음.File file =newFile("./keystore.json");// keystore 복호화.ObjectMapper objectMapper =ObjectMapperFactory.getObjectMapper();KeyStore keyStore =objectMapper.readValue(file,KeyStore.class);AbstractKeyring keyring =caver.wallet.keyring.decrypt(keyStore,"password");// caver wallet에 추가caver.wallet.add(keyring);BigInteger value =newBigInteger(caver.utils.convertToPeb(BigDecimal.ONE,"KLAY"));// 자산 이전 트랜잭션 생성ValueTransfer valueTransfer =caver.transaction.valueTransfer.create(TxPropertyBuilder.valueTransfer().setFrom(keyring.getAddress()).setTo("0x8084fed6b1847448c24692470fc3b2ed87f9eb47").setValue(value).setGas(BigInteger.valueOf(25000)) );// 트랜잭션 서명valueTransfer.sign(keyring);// Klaytn으로 트랜잭션 전송Bytes32 result =caver.rpc.klay.sendRawTransaction(valueTransfer.getRawTransaction()).send();if(result.hasError()) {thrownewRuntimeException(result.getError().getMessage()); }// 트랜잭션 영수증 확인 TransactionReceiptProcessor transactionReceiptProcessor = new PollingTransactionReceiptProcessor(caver, 1000, 15);
TransactionReceipt.TransactionReceiptData transactionReceipt = transactionReceiptProcessor.waitForTransactionReceipt(result.getResult());
}
caver-java 시작하기
Klaytn 노드에 접속하기
EN을 실행 중인 경우, 아래와 같이 호스트와 포트를 변경하여 자신의 노드에 연결할 수 있습니다:
Keyring은 저장되는 키 종류에 따라 3가지 타입으로 나뉩니다: 주소 1개와 개인키 1개를 가지는 SingleKeyring, 주소 1개와 여러 개인키를 가지는 MultipleKeyring, 그리고 주소 1개와 키 역할별로 개인키 1개 이상을 가지는 RoleBasedKeyring가 있습니다.
SingleKeyring는 내부에 key 속성을 정의하며, 이 key 속성에 개인키 1개가 저장됩니다.
MultipleKeyring는 내부에 keys 속성을 정의하며, 이 keys는 여러 개인키를 저장하기 위해 배열로서 구현됩니다.
RoleBasedKeyring에 정의되어 있는 keys 속성은 개인키 배열 3개를 요소로 갖는 List 객체로서 구현되어(keys가 비어있으면 [ [], [], [] ]와 같이 보임), 각 role이 사용하는 여러 개의 개인키가 저장될 수 있습니다. The first element of the array is filled with the private key(s) to be used for roleTransactionKey, the second element the private key(s) to be used for roleAccountUpdateKey, and the third element the private key(s) to be used for roleFeePayerKey.
role마다 다른 개인키를 사용하려면 caver.wallet.keyring.createWithRoleBasedKey를 사용해야 합니다. 배열의 각 요소는 RoleBasedKeyring에 있는 각 Role에 해당됩니다. 아래 예시는 각 Role이 사용하는 개인키들로부터 RoleBasedKeyring 인스턴스를 만드는 방법을 소개합니다.
String address ="0x{address in hex}";String[][] privateKeyArr =newString[][] {//roleTransactionKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },//roleAccountUpdateKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },//roleFeePayerKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },};RoleBasedKeyring keyring =caver.wallet.keyring.createWithRoleBasedKey(address,Arrays.asList(privateKeyArr));
키스토어 json 문자열로부터 Keyrings를 caver-java에 추가하기
Caver-java에서 제공하는 인메모리 지갑에 Keyring을 추가하면 더 쉽게 사용할 수 있습니다. 다음 예시는 Klaytn Wallet에서 만들어진 키스토어 JSON 문자열 파일을 사용해 caver.wallet에 Keyring을 추가하는 방법을 설명합니다.
위 결과를 살펴보면 caver.wallet에 Keyring을 추가하면 caver.wallet에서 여러분의 Keyring을 조회할 수 있습니다.
사용할 주소와 개인키만 있으면 caver.wallet.newKeyring로 손쉽게 Keyring을 만들고 caver.wallet에 직접 추가할 수 있습니다.
Caver caver =newCaver(Caver.MAINNET_URL);// 주소와 개인키를 월렛에 추가 AbstractKeyring addedSingleKeyring =caver.wallet.newKeyring("0x{address in hex}","0x{private key1}");// 주소와 개인키들을 월렛에 추가 String[] privateKeyArr =newString[] {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}",};AbstractKeyring addedMultipleKeyring =caver.wallet.newKeyring('0x{address in hex}', privateKeyArr);// 주소와 각 역할에 정의된 개인키를 월렛에 추가 String[][] privateKeyArr =newString[][] {//roleTransactionKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },//roleAccountUpdateKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },//roleFeePayerKey {"0x{privateKey in hex}","0x{privateKey in hex}","0x{privateKey in hex}", },};AbstractKeyring addedRoleBased =caver.wallet.newKeyring('0x{address in hex}',Arrays.asList(privateKeyArr))
개인키를 사용해 caver.wallet.newKeyring을 실행하면 개인키 1개를 가진 Keyring 인스턴스 1개가 생성되고 이 인스턴스는 caver.wallet에 추가됩니다. 다수의 개인키의 경우, 여러 개인키를 가진 Keyring 인스턴스 1개가 생성되고 caver.wallet에 추가됩니다. Role별로 1개 이상의 개인키를 가진 2차원 배열을 인자로 넘겨주면, Role마다 서로 다른 개인키(들)을 가진 Keyring 인스턴스 1개가 생성되며 이 역시 caver.wallet에 추가됩니다.
caver.wallet에 Keyring 인스턴스를 추가하면 caver.wallet.add 또는 caver.wallet.newKeyring은 Keyring 인스턴스를 반환합니다.
트랜잭션 전송하기
이 장에서는 Baobab 네트워크에서 caver-java를 사용하여 KLAY를 전송하는 방법을 보여줍니다.
Baobab Faucet을 통해 KLAY 받기
If you need KLAY for testing, you can get Baobab testnet KLAY from the Klaytn Wallet. 개인키 또는 키스토어 파일을 사용하여 Klaytn Wallet에 로그인하고 테스트를 위해 faucet을 통해 Baobab 테스트넷 KLAY를 받습니다.
송금 트랜잭션 전송
트랜잭션 서명은 caver-java 지갑을 통해 할 수 있습니다. 트랜잭션을 네트워크에 보내려면 아래와 같이 2단계를 거쳐야합니다.
트랜잭션 서명하기
만약, 사용하시고 싶은 Keyring이 caver.wallet에 있다면, caver.wallet.sign 함수로 서명할 수 있습니다.
caver.wallet에 Keyring을 추가하지 않고 따로 관리한다면, transaction.sign 함수를 통해 트랜잭션에 서명할 수 있습니다.
RLP 인코딩된 서명된 트랜잭션을 caver.rpc.klay.sendRawTransaction을 통해 Klaytn에 전송합니다.
위 코드는 Keyring을 caver.wallet에 추가하고, 트랜잭션을 생성하고, caver.wallet.sign를 통해 이 트랜잭션에 서명합니다.
위 코드를 실행하면 아래 결과를 얻습니다. 위 코드가 실행되었을 때, RLP 인코딩된 트랜잭션 문자열은 아래와 같이 나타납니다. (The RLP-encoded string output you got could be different from the string output shown below.)
위 예시와 같이 TransactionReceiptProcessor를 통해 트랜잭션을 전송한 결과를 가져올 수 있습니다. transactionHash 필드는 영수증 객체 내부에 정의됩니다.
트랜잭션이 블록에 추가된 후, txHash 문자열과caver.rpc.klay.getTransactionReceipt RPC 호출을 사용하여 언제든지 트랜잭션 영수증을 조회할 수 있습니다. 아래 예시는 caver.rpc.klay.getTransactionReceipt RPC 호출을 사용하여 영수증을 받는 방법을 보여줍니다.
트랜잭션의 실행 결과는 영수증의 status를 통하여 확인할 수 있습니다. 리턴값에 대한 자세한 설명은 caver.rpc.klay.getTransactionReceipt를 참조하세요. 만약 트랜잭션 실행이 실패한다면 에러에 대한 자세한 내용은 영수증의 txError에서 확인할 수 있습니다. txError에 대한 자세한 설명은 txError: Detailed Information of Transaction Failures를 참고하세요.
다른 트랜잭션 타입 실행하기
Klaytn은 확장성과 성능을 위한 다양한 트랜잭션 타입을 제공합니다. For more information, see Transactions. 이 장에서는 caver-java와 함께 사용할 수 있는 예시를 설명합니다.
트랜잭션 수수료 위임
Klaytn은 수수료 대납 기능을 제공합니다. 여기에서는, 여러분이 트랜잭션 전송자일 때 RLP 인코딩된 트랜잭션을 만드는 예시를 소개합니다.
The fee payer can send the transaction to the Klaytn after attaching the feePayerSignatures to the RLP-encoded string (rawTransaction) signed by the transaction sender. caver.wallet에 수수료 납부자 Keyring도 같이 있다면, caver.wallet.signAsFeePayer(feePayer.address, feeDelegatedTx)를 호출하여 수수료 납부자 서명을 feeDelegatedTx에 넣을 수 있습니다. 그렇지 않다면, 수수료 납부자는 트랜잭션 발신자가 서명한 RLP 인코딩된 문자열에서 feeDelegatedTx를 새로 만들고, 자신의 서명을 여기에 추가해야합니다. 아래 예시를 참고하십시오. 아래 예시를 직접 실행하려면 0x{RLP-encoded string}를 위 rlpEncoded 값으로 대체하십시오 .
The result of the transaction can be found through the status of the receipt. For the details of the return values, see caver.rpc.klay.getTransactionReceipt. If a transaction is failed, you can check more about the error in txError of the receipt. txError에 대한 자세한 설명은 [txError: Detailed Information of Transaction Failures]를 참고해주세요.
계정 업데이트
If you want to change the private key(s) for your Klaytn account, there are 3 important things you need to remember:
Klaytn은 자신에게 전송되는 모든 트랜잭션을 검증합니다.
트랜잭션을 검증하려면 개인키와 짝을 이루는 공개키가 필요합니다.
따라서, 기존에 사용하던 개인키를 새로운 개인키로 바꾸기 전에, 먼저 기존 공개키를 새로운 공개키로 바꿔야 합니다. 새로운 공개키는 반드시 새로운 개인키로부터 만들어야 합니다.
Keeping the 3 things above in your mind, you can change your private key(s) by following the steps below:
새로운 Keyring을 만들기 위해 새 개인키(들)을 준비합니다.
필요한 Keyring 타입(SingleKeyring, MultipleKeyring, RoleBasedKeyring)을 골라 Keyring을 만듭니다.
새 Keyring에서 Account 인스턴스를 생성합니다. 이 Account 인스턴스는 여러분의 Klaytn 계정이 사용할 새로운 공개키를 가지고 있습니다.
Account 인스턴스를 입력 파라미터로 받는 AccountUpdate 트랜잭션을 Klaytn에 전송합니다.
마지막으로, 기존 Keyring을 2번째 단계에서 만들었던 새 Keyring으로 교체합니다.
더 자세한 내용은 Account Update 를 확인하십시오.
AccountKey를 변경하려면, Account 인스턴스를 caver.transaction.type.AccountUpdate의 입력 변수 객체의 account 필드에 넣어야 합니다. Account 인스턴스는 Klaytn 계정의 주소와 업데이트할 AccountKey를 담고 있습니다.
아래 코드는 Klaytn 계정 개인키를 바꾸는 것과 더불어 Klaytn 계정 AccountKey를 AccountKeyPublic로 바꾸는 예시입니다. Don't forget to prepare your new private key(s).
위 코드가 성공적으로 실행되었다면 서명 시 기존 개인키와 이에 대응되는 기존 Keyring은 트랜잭션에 더 이상 사용하실 수 없습니다. 따라서 여러분은 caver.wallet.updateKeyring(newKeyring)을 사용해 기존 Keyring을 newKeyring으로 업데이트하셔야 합니다. Once it is updated, the signing will be done by the newly updated private key(s).
Klaytn 계정 AccountKey를 여러 개의 AccountKeys로 업데이트하려면 어떻게 해야 할까요? 아래 예시는 여러분이 사용하고 싶은 개인키들을 가지고 Account 인스턴스를 만드는 방법을 소개합니다(caver.account.create로 여러 공개키를 가지고 Account 인스턴스를 만들 수 있습니다.). 여기에서도, 트랜잭션 객체의 account 필드에 Account 인스턴스를 입력 파라미터로 넣으면, 나머지 업데이트 과정은 위에서 소개한 AccountKey 1개를 업데이트하는 과정과 동일합니다.
먼저, AccountKey를 AccountKeyWeightedMultiSig로 업데이트하기 위해 Account 인스턴스 하나를 만들어봅니다. AccountKeyWeightedMultiSig로 업데이트하려면, 임계값(Threshold)과 Key별 가중치가 정의되어야 합니다. 이를 위해서는 caver.account.weightedMultiSigOptions를 사용하십시오. 1번째 파라미터는 임계값이고 2번째 파라미터는 Key별 가중치를 담고 있는 배열입니다.
이제 AccountKeyRoleBased를 사용해 AccountKey를 업데이트합니다. AccountKeyRoleBased은 AccountKey 타입 중 하나이며 여기에는 각 role에서 사용하는 키가 정의되어 있습니다.
// Create an account instance with roles using AccountKeyRoleBased. In the account instance created, each role has a public key that corresponds to one private key.
List<String[]> newPrivateKeyArr =caver.wallet.keyring.generateRolBasedKeys(newint[] {1,1,1});RoleBasedKeyring newKeyring = caver.wallet.keyring.createWithRoleBasedKey(senderKeyring.getAddress(), newPrivateKeyArr);
const account =newKeyring.toAccount()
위 AccountKeyRoleBased는 Role마다 공개키 1개를 사용하는 예시입니다. 위 코드에서 볼 수 있듯이, 이들 각각은 개인키 1개에 대응됩니다. 각 Role마다 여러 개인키를 사용하고 싶다면 아래와 같이 각 Role마다 caver.account.weightedMultiSigOptions을 반드시 정의해야 합니다.
// AccountKeyRoleBased를 사용해 각 역할에 대해 키 [3, 2, 3]로 account 인스턴스 생성List<String[]> newPrivateKeyArr =caver.wallet.keyring.generateRolBasedKeys(newint[] {3,2,3});RoleBasedKeyring newKeyring = caver.wallet.keyring.createWithRoleBasedKey(senderKeyring.getAddress(), newPrivateKeyArr);
WeightedMultiSigOptions[] options =newWeightedMultiSigOptions[] { new WeightedMultiSigOptions(BigInteger.valueOf(4), Arrays.asList(BigInteger.valueOf(2), BigInteger.valueOf(2), BigInteger.valueOf(4))),
newWeightedMultiSigOptions(BigInteger.valueOf(2),Arrays.asList(BigInteger.valueOf(1),BigInteger.valueOf(1))), new WeightedMultiSigOptions(BigInteger.valueOf(3), Arrays.asList(BigInteger.valueOf(1), BigInteger.valueOf(1), BigInteger.valueOf(1))),
};Account account =newKeyring.toAccount(Arrays.asList(options));
AccountKey를 AccountKeyLegacy 또는 accountKeyFail로 업데이트하고 싶다면, 아래와 같이 Account 인스턴스를 만들고 이를 트랜잭션의 account 필드에 할당하십시오. 나머지 업데이트 과정은 다른 AccountKey 업데이트 과정과 동일합니다.
caver.contract 패키지에 있는 Contract 클래스를 사용하면 Klaytn의 스마트 컨트랙트와 쉽게 상호작용할 수 있습니다. 스마트 컨트랙트의 모든 함수는 하위수준 ABI가 주어졌을 때 자동으로 변환되어 contract 인스턴스내에 저장됩니다. 이는 스마트 컨트랙트를 마치 Java의 컨트랙트 인스턴스와 같이 다룰 수 있게 해줍니다.
이제 아래에서 간단한 솔리디티 예제 코드를 소개하면서 스마트 컨트랙트를 어떻게 다루는지 안내합니다. 'test.sol' 파일을 만들고 아래 예시를 작성합니다.
pragma solidity ^0.5.6;
contract KVstore {
mapping(string=>string) store;
function get(string memory key) public view returns (string memory) {
return store[key];
}
function set(string memory key, string memory value) public {
store[key] = value;
}
}
contract 인스턴스는 생성될 때 컨트랙트 주소를 contractAddress 속성으로 가집니다. 주소에는 getter / setter 함수 (getContractAddress() / setContractAddress())를 사용해 접근이 가능합니다.
contract 인스턴스가 생성되고 나면, 그 바이트코드와 생성자 인자(필요할 경우)를 아래와 같이 전달함으로써 스마트 컨트랙트를 배포할 수 있습니다.
contract 인스턴스의 deploy() 메서드가 컨트랙트 배포와 실행을 위한 트랜잭션을 보낸다는 사실에 유의하세요. 트랜잭션 전송 시에는 서명을 위해 caver.wallet에 있는 Keyrings를 사용합니다. 사용할 keyring은 caver.wallet에 서명하기 전에 먼저 추가해야 합니다.