대납을 통해서 ValueTransfer 를 하려고 하는데 invalid transaction v, r, s values of the sender 오류가 납니다

caver-java 버전: 1.3.1

테스트코드

@Test
public void testFeeDelegatedValueTransferTx() throws Exception {

    Caver caver  = Caver.build(Caver.BAOBAB_URL);
    KlayCredentials sender = KlayCredentials.create(operator1PrivateKey);

    TransactionManager transactionManager = new TransactionManager.Builder(caver, sender)
            .setChaindId(ChainId.BAOBAB_TESTNET).build();  // BAOBAB_TESTNET = 1001

    ValueTransferTransaction valueTransferTransaction = ValueTransferTransaction.create(
            sender.getAddress(),  // fromAddress
            investor3Address,  // toAddress
            Convert.toPeb("1", KLAY).toBigInteger(),    // value :  1 Klay
            BigInteger.valueOf(300_000)  // gasLimit
    );

    valueTransferTransaction.feeDelegate(); // feePayer = true
    String senderRawTransaction = transactionManager.sign(valueTransferTransaction).getValueAsString();  // isFeeDelegated : true

    // fee payer : 대납계정이다.
    KlayCredentials feePayer = KlayCredentials.create(deployAndFeePayerPrivateKey);
    FeePayerManager feePayerManager = new FeePayerManager.Builder(caver, feePayer)
            .setChainId(ChainId.BAOBAB_TESTNET).build();

    KlayTransactionReceipt.TransactionReceipt transactionReceipt = feePayerManager.executeTransaction(senderRawTransaction);

    String transactionHash = transactionReceipt.getTransactionHash();
    System.out.println("transactionHash = " + transactionHash);
}

결과:

17:33:05.702 [main] DEBUG org.web3j.protocol.http.HttpService - {“jsonrpc”:“2.0”,“id”:1,“error”:{“code”:-32000,“message”:“invalid transaction v, r, s values of the sender”}}

안녕하세요 :slight_smile:
코드 상으로는 문제가 없어 보이는데, 혹시 sender의 accountKey를 업데이트한 적이 있으신가요?

안녕하세요 :slight_smile:
클레이튼 / 블록체인을 공부하는 중이라서 말씀해주신 내용에 대한 확인방법이 궁금합니다.
sender 의 accountKey 를 업데이트를 시도했던적은 있던 것 같아서요.)

아, 그렇군요 !
그럼 트랜잭션에 서명할 때에 사용하신 private key는 어떤 private key인가요?
업데이트한 private key인가요? 아니면 업데이트하기 전 계정의 private key인가요?

만약 계정을 업데이트 하셨다면, 기존의 original private key - original public key - address 에서 new private key - new public key - address로 변경된 것입니다.
네트워크에는 address 계정은 앞으로 new public key를 사용한다고 저장되게 됩니다.

트랜잭션을 네트워크에 전송하게 되면 검증 과정을 거치는데요, 검증할 때 트랜잭션의 signatures에서 sender의 public key를 추출해서 네트워크에 저장된 계정의 AccountKey와 비교하게 됩니다.
계정을 업데이트했기 때문에 new public key가 서명에서 추출되어야 하는데, 실제로 추출된 것은 original public key라면 위와 같은 에러가 날 수 있습니다.

계정을 업데이트 했다면 아래와 같이 KlaytnWalletKey 포맷을 사용하여 credential을 생성하셔야 합니다.
KlayCredentials credentials = KlayCredentials.createWithKlaytnWalletKey("KlaytnWalletKeyFormat");

KlaytnWalletKey에 대한 자세한 내용은 KlaytnDocs를 참고해 주세요 :slight_smile:

안녕하세요.
친절하고 자세한 답변 감사합니다.

계정 업데이트 이후에 KlayCredentials 객체를 생성함에 있어서

KlayCredentials.create(“privateKey”)
KlayCredentials.createWithKlaytnWalletKey(“klaytnWalletKeyFormat”)

와의 차이점이 있을 것 같은데요.
어떤점 때문에 createWithKlaytnWalletKey 를 사용해야 하나요?

계정을 업데이트 하지 않았다면 계정의 키와 주소의 관계는 아래와 같습니다.
(original private key -> original public key) -> address
위의 같이 privat key에서 public key가 파생되고, 이 public key에서 address가 도출됩니다.

계정을 업데이트 한다는 것은 위의 강결합 관계를 끊어버리고 address를 주소로 가지는 계정에서 사용하는 private key, public key쌍을 변경하는 것입니다.

만약 새롭게 사용할 키를 new private key , new public key라고 가정한다면 업데이트 이후에는
(new private key -> new public key) - address
위와 같은 관계를 가지게 되는 것입니다.

그렇기 때문에 계정 업데이트 이후에는 new private key를 사용해야 합니다.

KlaytnWalletKey는 "0x{private key}0x000x{address in hex}"의 형태로 업데이트된 계정의 키와 주소를 나타낼 수 있는 형태입니다.

KlaytCredential.create의 파라미터는 private key string 형태입니다.
그렇기 때문에 new private key를 파라미터로 전달하게 되면 new private key -> new public key -> new address로 도출하여 new address를 주소로 가지는 아예 다른 credential이 생성되게 됩니다.

만약 original private key를 파라미터로 전달한다면 original private key -> original public key -> address로 도출되어 address를 주소로 가지는 credential이 생성되지만, 서명할 때에 original private key가 사용되게 됩니다.
이미 Klaytn 네트워크에는 address 계정은 새로운 키(new private key, new public key)를 사용할 것이라고 업데이트가 된 상태이기 때문에 만약 original private key로 서명한 트랜잭션이 전송되면 검증 과정에서 실패하게 됩니다.

그래서 KlaytnWalletKey를 사용해야 하는 것입니다
KlayCredentials.createWithKlaytnWalletKey(“0x{new private key}0x000x{address}”)를 사용하면 address를 주소로 가지고 서명할 때에 new private key를 사용하는 credential이 생성되게 됩니다.

네, :slight_smile:
도움이 많이 되었습니다.
답변 감사드립니다.
자주 여쭙도록 하겠습니다.
ㅎㅎ 번창하세요.

1개의 좋아요