Caver.js Timeout options 질문

  private async sendTransactionByPayer(
    feeDelegated: Caver.transaction.feeDelegatedValueTransfer,
    privateKey: string,
    feePayerAddress: string,
    feePrivateKey: string
  ) {
    await feeDelegated.sign(
      this.caver.wallet.keyring.createFromPrivateKey(privateKey)
    )
    await feeDelegated.signAsFeePayer(
      new this.caver.wallet.keyring.singleKeyring(
        feePayerAddress,
        feePrivateKey
      )
    )

    const receipt = await this.caver.rpc.klay.sendRawTransaction(feeDelegated)
    return receipt.transactionHash
  }

위 로직으로 트랜잭션을 전송하고 있습니다.

성공응답을 받는데 까지 수백초가 소요되기 때문에 해결방안을 생각했습니다.

  1. txid를 broadcast 전에 먼저 뽑아낸다

  2. timeout 옵션을 통해 너무 오래걸릴 경우 node 와의 통신을 클라이언트(코드가 존재하는 서버)가 먼저 끊는다.


    // 아래 두개 옵션 모두 동작하지 않습니다.
    const provider = new Caver.providers.HttpProvider(this.config.PROVIDER, { timeout: 1 });
    this.caver = new Caver(provider, { timeout: 1 });

   // ....

  private async sendTransactionByPayer(
    feeDelegated: Caver.transaction.feeDelegatedValueTransfer,
    privateKey: string,
    feePayerAddress: string,
    feePrivateKey: string
  ) {
    await feeDelegated.sign(
      this.caver.wallet.keyring.createFromPrivateKey(privateKey)
    )
    await feeDelegated.signAsFeePayer(
      new this.caver.wallet.keyring.singleKeyring(
        feePayerAddress,
        feePrivateKey
      )
    )
    const txid = this.caver.utils.keccak256(feeDelegated.getRLPEncoding()) // ## 1번


    try {
      const receipt = await this.caver.rpc.klay.sendRawTransaction(feeDelegated)
      return receipt.transactionHash
    } catch (e) { // timeout error point
      console.log(e.toString(), txid)
      return txid
    }
  }

질문 1. 그런데 어째서인지 timeout 옵션이 동작하지 않습니다. 혹시 제 코드가 잘못된걸까요??
caver.js ^1.5.5 에서 1.5.7로 업데이트해도 똑같습니다.
일부로 테스트를 위해 timeout : 1로 설정후 init해도 어떠한 에러가 발생하지 않습니다.

질문 2. txid를 뽑아내는 로직에 문제가 없을지 확인 부탁드립니다 (docs를 보긴했지만…)

질문 3. 해당 로직에 문제가 있을까요?

  • 만약 클라이언트 단에서 먼저 timeout option을 통해 통신을 끝낸다고 해도, klaytn EN노드는 계속 broadcast작업을 이어가나요? (또는 그 스레드를 종료하지 않나요?)

아 일단 1.6.4를 다시 지우고 깔아보니까 아예 ts지원으로 바뀐건지 오류가 나네요… 1.5.4 > 1.5.7 기준으로 하겠습니다

안녕하세요

request.timeout = this.timeout && this.timeout !== 1 ? this.timeout : 0 이런 로직이 HttpProvider에 있는데요, timeout을 설정하려면 1이 아닌 값으로 해야합니다.

txid가 transaction hash를 말씀하시는 거라면 eventEmitter를 사용해도 됩니다.
caver.rpc.klay.sendRawTransaction('0x08f88...').on('transactionHash', h => {...})

답변 감사합니다.

아래와 같은 현재 구조상 미들웨어에서 "스케줄러의 요청"에대해 빠르게 응답(txHash)해야 합니다.

  • 스케줄러[DB read/write, 응답받은 txHash db update] → klaytn 미들웨어 (caverjs 이용 API) → Endpoint Node

따라서 eventEmitter를 사용할 수는 없을거같습니다 (스케줄러입장에선 미들웨어에서 응답(txHash) 느리게 오기때문에, 스케줄러 요청은 timeout connection close됩니다)

  1. 따라서 빠르게 txHash 응답을 주는것을 목적으로 설계한다고하면
    결국 EN노드에서 응답이 느리면, connection 을 빠르게 끊어야합니다.

그런데 만약 EN노드와의 통신을 끝낸다고 해도, klaytn EN노드는 계속 broadcast작업을 이어나갈지 궁금합니다.
( 만약 timeout했다고 그 transaction은 broadcast하지 않을지 걱정되네요 = 무조건 실패)

  1. 혹시 아래 txHash 를 뽑아내는 로직에 문제가 없을까요?
    const txid = this.caver.utils.keccak256(feeDelegated.getRLPEncoding())

노드와의 통신을 끊었을 때 노드가 트랜잭션을 정상적으로 받은 이후에 통신이 끊겼을 경우에는 무관하지만, 그렇지 않은 경우에는 트랜잭션 전송에 문제가 있을 수 있습니다.
노드로부터 트랜잭션 해시를 리턴받으면 노드가 트랜잭션을 전송을 정상적으로 받았다는 의미이기 때문에 해당값을 체크하지 않고는 노드가 정상적으로 트랜잭션을 받아서 처리한다는 것을 보장할 수 없습니다.

트랜잭션 해시는 from, feepayer의 서명값이 모두 채워진 이후에 feeDelegated.getTransactionHash 함수를 호출하면 됩니다.

음 통신을 강제 종료하는것에 문제가 있다면, 단순히 응답을 날리고 await 하며 기다리지 않는 구조로 사용하고자 합니다. (왜냐하면 현재 너무 응답이 길어져서, 기다릴 수 없는 상황입니다.)

feeDelegated.getTransactionHash가 있군요. 감사합니다.

function send() {
    caver.rpc.klay.sendRawTransaction('0x08f88...')
        .on('transactionHash', h => console.log) // do nothing, just print
     return feeDelegated.getTransactionHash()
}

@Jamie 추가 질문 드립니다. 다른 rpc 통신은 (getLastblock 등) timeout 옵션이 잘 적용되는것으로 보입니다.

하지만 sendRawTransaction의 경우는 timeout 옵션이 적용되지 않은데 혹시 해당건에 대해서 알 수 있을까요?

(제 추측으로는 caver.klay.sendRawTransaction 내부에서 broadcast에 대한 응답은 바로 받지만, event를 wait하고 있는거같긴합니다)

예를들어 timeout 시간을 2초로 하고 send가 아닌 rpc call을 하면 Connection error : couldn't connect to node .... 에러가 발생하지만, send를 할때는 발생하지 않는거같습니다.

네트워크로 트랜잭션을 전송하는 rpc call의 경우(예를 들어 sendTransaction, sendTransactionAsFeePayer, sendRawTransaction), 트랜잭션을 전송하는 요청을 보내고 받은 해시값으로 해당 트랜잭션이 처리된 결과를 받기 위해서 caver.rpc.klay.getTransactionReceipt 요청을 계속 보냅니다.

그러므로 sendRawTransaction을 보내고 해시를 받는데까지 timeout 시간을 넘기지 않으면 정상적으로 다음 receipt을 폴링하는 단계로 넘어가며, 해당 단계에서도 각 요청마다 timeout 시간을 넘지 않으면 위 Connection error : couldn't connect to node .... 에러가 발생하지 않게됩니다

참고로 timeout는 각 rpc call마다 적용됩니다.

caver.rpc.klay.getTransactionReceipt 정상으로 응답할때까지 기다리는 이유가 있을까요?

이 시간이 상당히 소요되는데, 그냥 broadcast / getTransactionReceipt 를 제가 직접 제어하고 싶습니다.

관련 mehtod가 있을까요?

await를 안걸고 그냥 넘어가는데 문제있으신가요?
지금 노드로 트랜잭션을 전송하면 기본적으로 결과 receipt을 반환하도록 로직이 되어있어서 따로 명확하게 구분해서 할 수 있는 기능은 따로 제공되지 않습니다.
그렇게 하려면 caver.rpc.klay를 사용하지 못하고 provider를 사용해서 payload를 직접 만들어서 보내야 합니다.
getTransactionReceipt은 따로 rpc call 제공되고 있습니다.

음 이해했습니다 :smile:

await를 안걸고 그냥 하겠습니다

1 Like