Failed to do wallet call. Caused by: An error happened during the call: 2: Couldn't send message

I have deployed 2 canisters on ICP,

x5kf3-raaaa-aaaah-aq2xq-cai, which provides a build_witness function

#[update]
fn build_witness(tx_id_hex: String, sign_hashes_hex: Vec<String>)->(bool, Vec<u8>){
    let available_cycles = msg_cycles_available();
    if available_cycles < BUILD_WITNESS_FEE {
        ic_cdk::eprintln!("Not enough cycles provided for get build witness operation.");
        return (false, "Not enough cycles provided for get build witness operation.".as_bytes().to_vec());
    }
    let _ = msg_cycles_accept(BUILD_WITNESS_FEE);

    let tx_id_bytes =  match hex::decode(tx_id_hex.clone()){
        Ok(bytes) => bytes,
        Err(e) => {
            ic_cdk::eprintln!("hex::decode error {:?}", e);
            return (false, format!("hex::decode error {:?}", e).as_bytes().to_vec());
        }
    };

    let mut sign_hashes_bytes = Vec::with_capacity(sign_hashes_hex.len());
    for hash in &sign_hashes_hex {
        let hash_bytes =  match hex::decode(hash.clone()){
            Ok(bytes) => bytes,
            Err(e) => {
                ic_cdk::eprintln!("hex::decode error {:?}", e);
                return (false, format!("hex::decode error {:?}", e).as_bytes().to_vec());
            }
        };
        sign_hashes_bytes.push(hash_bytes);
    }
    
    let genesis_sc_root = GENESIS_SC_ROOT.with(|p| p.borrow().clone());

    let witness = match witness::build_public_witness(genesis_sc_root.as_bytes(),&tx_id_bytes, &sign_hashes_bytes){
        Ok(witness) => witness,
        Err(e) => {
            ic_cdk::eprintln!("witness::build_public_witness error {:?}", e);
            return (false, format!("witness::build_public_witness error {:?}", e).as_bytes().to_vec());
        }
    };
    ic_cdk::println!("witness:{}", hex::encode(witness.clone()));
    return (true, witness)
}

xbsjj-qaaaa-aaaai-aqamq-cai, which provides 2 funcitons

#[update]
pub async fn verify_and_sign(tx_id_hex :String, sign_hashes_hex: Vec<String>, proof_hex:String) -> (bool, Vec<String>) {
    let available_cycles = msg_cycles_available();
    let needed_cycles = PLONK_VERIY_FEE + BUILD_WITNESS_FEE + SIGN_WITH_ECDSA_FEE;
    ic_cdk::println!("available_cycles:{:?}, needed_cycles:{:?}", available_cycles, needed_cycles);
    if available_cycles < needed_cycles {
        ic_cdk::eprintln!("Not enough cycles provided for get sign hashes operation.");
        return (false, vec![]);
    }
    let _ = msg_cycles_accept(needed_cycles);


    let derivation_path = DERIVATION_PATH.with(|d| d.clone());
    let key_name = KEY_NAME.with(|kn| kn.borrow().to_string());
    ic_cdk::println!("tx_hex:{:?}, sign_hashes_hex:{:?}, proof_hex:{:?}", tx_id_hex, sign_hashes_hex, proof_hex);
    
    let proof_bytes =  match hex::decode(proof_hex){
        Ok(bytes) => bytes,
        Err(e) => {
            ic_cdk::eprintln!("hex::decode error {:?}", e);
            return (false, vec![]);
        }   
    };

    //build public witness 
    let witness_builder = WITNESS_BUILDER_CANISTER.with(|d| d.borrow().clone());  
    let (build_witness_success, witness_bytes): (bool,Vec<u8>)= match call_with_payment(witness_builder, "build_witness", (tx_id_hex.clone(), sign_hashes_hex.clone()), BUILD_WITNESS_FEE).await {
        Ok((build_witness_success, witness_bytes)) => (build_witness_success, witness_bytes),
        Err(err) => {
            // Handle the error here
            ic_cdk::eprintln!("build_public_witness error: {:?}", err);
            // Return a default value or handle it appropriately
            return (false, vec![])
        }
    };

    if !build_witness_success{
        ic_cdk::eprintln!("build_public_witness failed");
        return (false, vec![]);
    } 

    //verify  
    let plonk_verifier = PLONK_VERIFIER_CANISTER.with(|d: &RefCell<Principal>| d.borrow().clone());  
    let zk_valid: bool = match call_with_payment(plonk_verifier, "plonk_verify", (proof_bytes, witness_bytes,), PLONK_VERIY_FEE).await {
        Ok((valid,)) => valid,
        Err(err) => {
            // Handle the error here
            ic_cdk::eprintln!("plonk verify error: {:?}", err);
            // Return a default value or handle it appropriately
            return (false, vec![])
        }
    };

    if !zk_valid {
        ic_cdk::eprintln!("plonk verify failed");
        return (false, vec![]);
    }

    let mut sigs = Vec::with_capacity(sign_hashes_hex.len());
    for hash in &sign_hashes_hex {
        ic_cdk::println!("{}", hash);
        let hash_bytes = match hex::decode(hash) {
            Ok(bytes) => bytes,
            Err(e) => {
                ic_cdk::eprintln!("hex::decode error {:?}", e);
                return (false, vec![]);
            }
        };
        let sig = ecdsa_api::sign(key_name.clone(), derivation_path.clone(), hash_bytes.clone()).await;
        ic_cdk::println!("hash:{}, sig:{}", hash, hex::encode(sig.clone()));
        sigs.push(hex::encode(sig));
    }

   (true, sigs)
}

and

#[update]
pub async fn verify_and_sign_free(tx_id_hex :String, sign_hashes_hex: Vec<String>, proof_hex:String) -> (bool, Vec<String>) {
    let derivation_path = DERIVATION_PATH.with(|d| d.clone());
    let key_name = KEY_NAME.with(|kn| kn.borrow().to_string());
    ic_cdk::println!("tx_hex:{:?}, sign_hashes_hex:{:?}, proof_hex:{:?}", tx_id_hex, sign_hashes_hex, proof_hex);
    
    let proof_bytes =  match hex::decode(proof_hex){
        Ok(bytes) => bytes,
        Err(e) => {
            ic_cdk::eprintln!("hex::decode error {:?}", e);
            return (false, vec![]);
        }   
    };

    //build public witness 
    let witness_builder = WITNESS_BUILDER_CANISTER.with(|d| d.borrow().clone());  
    let (build_witness_success, witness_bytes): (bool,Vec<u8>)= match call_with_payment(witness_builder, "build_witness", (tx_id_hex.clone(), sign_hashes_hex.clone()), BUILD_WITNESS_FEE).await {
        Ok((build_witness_success, witness_bytes)) => (build_witness_success, witness_bytes),
        Err(err) => {
            // Handle the error here
            ic_cdk::eprintln!("build_public_witness error: {:?}", err);
            // Return a default value or handle it appropriately
            return (false, vec![])
        }
    };

    if !build_witness_success{
        ic_cdk::eprintln!("build_public_witness failed");
        return (false, vec![]);
    } 

    //verify  
    let plonk_verifier = PLONK_VERIFIER_CANISTER.with(|d: &RefCell<Principal>| d.borrow().clone());  
    let zk_valid: bool = match call_with_payment(plonk_verifier, "plonk_verify", (proof_bytes, witness_bytes,), PLONK_VERIY_FEE).await {
        Ok((valid,)) => valid,
        Err(err) => {
            // Handle the error here
            ic_cdk::eprintln!("plonk verify error: {:?}", err);
            // Return a default value or handle it appropriately
            return (false, vec![])
        }
    };

    if !zk_valid {
        ic_cdk::eprintln!("plonk verify failed");
        return (false, vec![]);
    }

    let mut sigs = Vec::with_capacity(sign_hashes_hex.len());
    for hash in &sign_hashes_hex {
        ic_cdk::println!("{}", hash);
        let hash_bytes = match hex::decode(hash) {
            Ok(bytes) => bytes,
            Err(e) => {
                ic_cdk::eprintln!("hex::decode error {:?}", e);
                return (false, vec![]);
            }
        };
        let sig = ecdsa_api::sign(key_name.clone(), derivation_path.clone(), hash_bytes.clone()).await;
        ic_cdk::println!("hash:{}, sig:{}", hash, hex::encode(sig.clone()));
        sigs.push(hex::encode(sig));
    }

   (true, sigs)
}

verify_and_sign_free is a cycles free version of verify_and_sign.

Test Steps

1. call x5kf3-raaaa-aaaah-aq2xq-cai with user pay cycles, it works as expceted.

dfx canister call x5kf3-raaaa-aaaah-aq2xq-cai build_witness '("98da4b13e7508b84712850e723b0f2f339e93df6250a0e93af7f231e85fdac8b", vec{"2cb50594fb592826b00b7e83d70ad96feef2a55a183222409883e1bfc6022662"})' --network ic --with-cycles 100000000 --wallet 4ichq-aqaaa-aaaak-qcosa-cai

(
  true,
  blob "\00\00\00\14\00\00\00\00\00\00\00\14\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\98\da\4b\13\e7\50\8b\84\71\28\50\e7\23\b0\f2\f3\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\39\e9\3d\f6\25\0a\0e\93\af\7f\23\1e\85\fd\ac\8b\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\2c\b5\05\94\fb\59\28\26\b0\0b\7e\83\d7\0a\d9\6f\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\ee\f2\a5\5a\18\32\22\40\98\83\e1\bf\c6\02\26\62\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\5b\96\db\d1\59\14\12\77\77\ef\58\37\32\79\b5\7e\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\c9\ca\81\6e\1f\7b\34\c4\3e\ad\9c\03\bb\46\36\4d",
)

2. If I call xbsjj-qaaaa-aaaai-aqamq-cai verify_and_sign_free function, it works as expected.

dfx canister call xbsjj-qaaaa-aaaai-aqamq-cai verify_and_sign_free '("98da4b13e7508b84712850e723b0f2f339e93df6250a0e93af7f231e85fdac8b", vec {"2cb50594fb592826b00b7e83d70ad96feef2a55a183222409883e1bfc6022662"}, "229baaee55571d2454fa2ba9f32e2b07135f0e10972009fd5e8a07b7e4025fe300ae9f755de6d73c11a82eb1b2cbc4fd2ba28c20fc215e51b7201ba31e262eb819709d1d8cfe03e7699b894d71052e6ccb5324c89825c2ecdf46d784f4a2e91510ac3e74bd63e57cd443ab4e8df6f8076742bf9a9e17cb61df35d08241eca8222c02e4390122e9c4b7bebb4a704fd78d96dba4cde80500e7240e15713301a4f8065fe4df227810ad02291f579fab794d24cba12c75c864fd47fcaa96343d2cfe05080197de901ad51b89e1035c6157b658f7b730a952e742b16ab99bb324307e12b6c16a4b4d0edd3af9d1eed0cc0ea001a8f1f3499f770ec6dd943119428db5100ac6efb2d4474c879247fd8d7132e33332c544fced798f85e24230bfd402890144705cf054a8784adf374e32da9729e541ee52963533a4a84abb04b83926aa03d7f95792708d08ae265db38423f35d5cf7b4203ccb28f0d330a7e0de694b6d0f324015bf06d3f7c5e8b5bc9f05018d98d8744f4ae99b16992adcc2b567704c1d7a69ec4b67334842aa1f105c00492fd92898a12b623ae942b0d27257c825191d2391cdc920925c37eddc3955bac7c562891b4f312a77b6cfd14beb54313bab0f92f3aa7b28e0756e51d2b6acee7f91c06f599ef8ac0fc84f3e9ca1a29f7dba05b1fc6dbb885994c78effe92941b231195cf990f4684ce80c8561840418de87134c1940edb3d7bfdc49c7202e28e795bd0547daee1e788764205c5e9b0995552896972dc9f8c8dc460f1b5a16db62ccf95fd27d02ec8972e69ee3e513bc43f01f2202ae9a09043697d1c5d49ed51813d81f51efc2aade8e480d8fff7014b6f41d09419fc87a071f116d4a04ffe99e50016b5b73bdd357c7fd72f0ac4bae6dbe25178b4dd99fe080c219741ccec1e2d713a29f9f4dd97ca323fbb9b49f572672022552b85f7e78be4dae71d3fd2adeef4549c4c584bc9787c51599a6f73c84382768aa27767f314f07cd3b8bcc4bb842daf2b3f43c9918e3513652ad8c9205071403995b6014a4dd5ef2fa03f1b497d0ec387be2a5f4c044f0f33f222a6e8ed5065ae326e0a46db583e874ce5567f0a215ed80ab39fa49159579529b5808f891012accdbb8424f962502df0a3b88b1abeca31104ae5094e83f4121b4774bd94621811743f001c3cb970bfc1f7b0125429963df1c8e4164183b38ad15cfacce942bd22ebc1146292580cee8469b4d870f4e3093987d2efbdb9e3e2147fbbfe0332835a812b42955a77a17c659c8c7b582e05874833abef31cdeb2c2c5b718de13")' --network ic
(
  true,
  vec {
    "7bc8a0bcec5d8e707eea512d819e8d1e5441cd0d328a2c9bd67146634c41a1af1df605305e077d8631310fa990fbd4690533931750f67535f785479d325d7109";
  },
)

3. If I call xbsjj-qaaaa-aaaai-aqamq-cai verify_and_sign, it resports “Couldn’t send messge”

 %dfx canister call xbsjj-qaaaa-aaaai-aqamq-cai verify_and_sign '("98da4b13e7508b84712850e723b0f2f339e93df6250a0e93af7f231e85fdac8b", vec {"2cb50594fb592826b00b7e83d70ad96feef2a55a183222409883e1bfc6022662"}, "229baaee55571d2454fa2ba9f32e2b07135f0e10972009fd5e8a07b7e4025fe300ae9f755de6d73c11a82eb1b2cbc4fd2ba28c20fc215e51b7201ba31e262eb819709d1d8cfe03e7699b894d71052e6ccb5324c89825c2ecdf46d784f4a2e91510ac3e74bd63e57cd443ab4e8df6f8076742bf9a9e17cb61df35d08241eca8222c02e4390122e9c4b7bebb4a704fd78d96dba4cde80500e7240e15713301a4f8065fe4df227810ad02291f579fab794d24cba12c75c864fd47fcaa96343d2cfe05080197de901ad51b89e1035c6157b658f7b730a952e742b16ab99bb324307e12b6c16a4b4d0edd3af9d1eed0cc0ea001a8f1f3499f770ec6dd943119428db5100ac6efb2d4474c879247fd8d7132e33332c544fced798f85e24230bfd402890144705cf054a8784adf374e32da9729e541ee52963533a4a84abb04b83926aa03d7f95792708d08ae265db38423f35d5cf7b4203ccb28f0d330a7e0de694b6d0f324015bf06d3f7c5e8b5bc9f05018d98d8744f4ae99b16992adcc2b567704c1d7a69ec4b67334842aa1f105c00492fd92898a12b623ae942b0d27257c825191d2391cdc920925c37eddc3955bac7c562891b4f312a77b6cfd14beb54313bab0f92f3aa7b28e0756e51d2b6acee7f91c06f599ef8ac0fc84f3e9ca1a29f7dba05b1fc6dbb885994c78effe92941b231195cf990f4684ce80c8561840418de87134c1940edb3d7bfdc49c7202e28e795bd0547daee1e788764205c5e9b0995552896972dc9f8c8dc460f1b5a16db62ccf95fd27d02ec8972e69ee3e513bc43f01f2202ae9a09043697d1c5d49ed51813d81f51efc2aade8e480d8fff7014b6f41d09419fc87a071f116d4a04ffe99e50016b5b73bdd357c7fd72f0ac4bae6dbe25178b4dd99fe080c219741ccec1e2d713a29f9f4dd97ca323fbb9b49f572672022552b85f7e78be4dae71d3fd2adeef4549c4c584bc9787c51599a6f73c84382768aa27767f314f07cd3b8bcc4bb842daf2b3f43c9918e3513652ad8c9205071403995b6014a4dd5ef2fa03f1b497d0ec387be2a5f4c044f0f33f222a6e8ed5065ae326e0a46db583e874ce5567f0a215ed80ab39fa49159579529b5808f891012accdbb8424f962502df0a3b88b1abeca31104ae5094e83f4121b4774bd94621811743f001c3cb970bfc1f7b0125429963df1c8e4164183b38ad15cfacce942bd22ebc1146292580cee8469b4d870f4e3093987d2efbdb9e3e2147fbbfe0332835a812b42955a77a17c659c8c7b582e05874833abef31cdeb2c2c5b718de13")' --network ic --with-cycles 28000000000 --wallet 4ichq-aqaaa-aaaak-qcosa-cai

Error: Failed to do wallet call.
Caused by: An error happened during the call: 2: Couldn't send message

4. I check my cycles, enough cycles in this wallet.

dfx cycles balance --network ic
6.999 TC (trillion cycles).

The following is the snapshot of execution records with dfx v0.22.0

Anybody have idea about this problem?

The error could be here. dfx cycles balance checks how many cycles you have on the cycles ledger. If you make a call via --wallet <wallet id> the the balance of the wallet canister is relevant. dfx canister status --ic <wallet id> will tell you how many cycles the wallet has

Edit: just tried with my own wallet that has a bunch of cycles. Worked fine

1 Like

@Severin It works after top-up wallet canister, thanks very much.

1 Like