the canister ID is: ukk5v-3yaaa-aaaam-ach6q-cai
I do use Motoko. that is correct.
I believe so, I can verify in just a bit.
the URLs are:
https://icp-api.io//api/v2/canister/rrkah-fqaaa-aaaaa-aaaaq-cai//read_state
and
https://icp-api.io//api/v2/canister/rrkah-fqaaa-aaaaa-aaaaq-cai//call
I don’t have the exact times of the failures, but I am about to resume investigating the issue, so within the a few minutes, I’ll be able to give you the time of my most recent attempt.
there is quite a bit of code that is responsible for performing the ECDSA signed HTTPS outcalls to the governance canister. here are the snippets:
This is the function that makes the call and below it, are the definitions of the functions that this function references.
public func getNeuronData(input: TreasuryTypes.GetNeuronDataInput): async TreasuryTypes.GetNeuronDataOutput{
let {args; selfAuthPrincipal; public_key; transformFn; method_name} = input;
let sender = selfAuthPrincipal;
let canister_id: Principal = Principal.fromText(Governance.CANISTER_ID);
let request = EcdsaHelperMethods.prepareCanisterCallViaEcdsa({sender; public_key; canister_id; args = to_candid(args); method_name;});
let {envelopeCborEncoded} = await EcdsaHelperMethods.getSignedEnvelope(request);
let headers = [ {name = "content-type"; value= "application/cbor"}];
let {request_url = url; envelope_content} = request;
let body = ?Blob.fromArray(envelopeCborEncoded);
let method = #post;
let max_response_bytes: ?Nat64 = ?Nat64.fromNat(1024 * 1024);
let transform = ?{ function = transformFn; context = Blob.fromArray([]); };
let ic : IC.Self = actor("aaaaa-aa");
let http_request = {body; url; headers; transform; method; max_response_bytes};
Cycles.add<system>(20_949_972_000);
let {status; body = responseBody; headers = headers_;} : IC.http_response = await ic.http_request(http_request);
let response = { status; body = responseBody; headers = headers_; };
let envelopeContentInMajorType5Format = EcdsaHelperMethods.formatEnvelopeContentForRepIndHash(envelope_content);
let {ingress_expiry} = envelope_content;
let requestId: Blob = Blob.fromArray(RepresentationIndependentHash.hash_val(envelopeContentInMajorType5Format));
return {response; requestId; ingress_expiry;};
};
public func prepareCanisterCallViaEcdsa(arguments: PrepareCanisterCallViaEcdsaArgs): CanisterEcdsaRequest {
let {canister_id; sender; method_name; args; public_key} = arguments;
let arg = Blob.toArray(args);
let request_url : Text = IC_URL # "/api/v2/canister/" # Principal.toText(canister_id) # "/call";
let key_id = { name : Text = "key_1"; curve : IC.ecdsa_curve = #secp256k1};
let ingress_expiry : Nat64 = Nat64.fromNat(Int.abs(Time.now())) + (3 * 60 * 1_000_000_000);
let envelope_content : EnvelopeContent = { ingress_expiry; canister_id; method_name; arg; sender};
return { request_url; envelope_content; key_id; public_key = Blob.toArray(public_key) };
};
public func getSignedEnvelope(request : CanisterEcdsaRequest) :
async {envelopeCborEncoded: [Nat8]}{
let {envelope_content; key_id; public_key} = request;
let envelopeContentInMajorType5Format = formatEnvelopeContentForCborEncoding(envelope_content);
let {message_hash;} = getMessageHashForEcdsaSignature(formatEnvelopeContentForRepIndHash(envelope_content));
Cycles.add<system>(25_000_000_000);
let { signature } = await ic.sign_with_ecdsa({ message_hash; derivation_path = []; key_id;});
let envelopeAsMajorType : Value.Value = #majorType5([
(#majorType3("content"), #majorType5(envelopeContentInMajorType5Format)),
(#majorType3("sender_pubkey"), #majorType2(public_key)),
(#majorType3("sender_sig"), #majorType2(Blob.toArray(signature)))
]);
let envelopeCborEncoded : [Nat8] = switch(Encoder.encode(envelopeAsMajorType)) {
case (#err(e)) {throw Error.reject("envelope encoding falied") };
case(#ok(encoding)) {encoding};
};
return {envelopeCborEncoded};
};
public func formatEnvelopeContentForRepIndHash(envelope_content: EnvelopeContent) : RepresentationIndependentHash.Value {
let { ingress_expiry; sender; canister_id; method_name; arg } = envelope_content;
let envelopeContentInRepIndHashableFormat = ([
("request_type", #Text("call")),
("ingress_expiry", #Nat(Nat64.toNat(ingress_expiry))),
("method_name", #Text(method_name)),
("sender", #Blob(Principal.toBlob(sender))),
("canister_id", #Blob(Principal.toBlob(canister_id))),
("arg", #Blob(Blob.fromArray(arg)))
]);
return #Map(envelopeContentInRepIndHashableFormat);
};
public func hash_val(v : Value) : [Nat8] {
encode_val(v) |> Sha256.sha256(_)
};
func encode_val(v : Value) : [Nat8] {
switch (v) {
case (#Blob(b)) { Blob.toArray(b) };
case (#Text(t)) { Blob.toArray(Text.encodeUtf8(t)) };
case (#Nat(n)) { leb128(n) };
case (#Int(i)) { sleb128(i) };
case (#Array(a)) { arrayConcat(Iter.map(a.vals(), hash_val)); };
case (#Map(m)) {
let entries : Buffer.Buffer<Blob> = Buffer.fromIter(Iter.map(m.vals(), func ((k : Text, v : Value)) : Blob {
Blob.fromArray(arrayConcat([ hash_val(#Text(k)), hash_val(v) ].vals()));
}));
entries.sort(Blob.compare); // No Array.compare, so go through blob
arrayConcat(Iter.map(entries.vals(), Blob.toArray));
}
}
};