Error: source chain head has moved since the bundle began

Hi all -

Over in another thread, I’m having some problems trying to issue a cap grant to a specific user from the UI.

In playing around with some different approaches, I am now getting this very explicit error message which I don’t know how to interpret:
Source chain error: Attempted to commit a bundle to the source chain, but the source chain head has moved since the bundle began. Bundle head: Some(HeaderHash(uhCkkfPa-dLkjuoDSdnmPFuTFPE641mU_X6edUGWm_PK9FZwQOnxl)), Current head: Some((HeaderHash(uhCkkfcey7GrtytIFnw3NwyjwztLrbxSfdY3sZqpomaxKoiFjZ_Au), 8, Timestamp(2021-12-11T09:03:14.832563Z)))

What does this mean exactly?
To trigger this error all I have done is make an entry (a private entry to the users source chain), and then call a ‘create_cap_claim’ function using another users agentpubkey.

Thanks - alex.

If you call two zome functions in a row, from a client, the second without waiting for the response to the first, then you can get this error.

Two ways to solve, depending on your use case, are

  1. wait for zome call 1 asynchronous completion before making zome call 2
  2. switch ChainTopOrdering input using a CreateInput and a create call (instead of create_entry)

https://docs.rs/hdk/latest/hdk/prelude/enum.ChainTopOrdering.html
https://docs.rs/hdk/latest/hdk/prelude/struct.CreateInput.html

The ChainTopOrdering link has a good explainer of what this is all about

Btw maybe rename the thread slightly so that other people could find it easier if they searched for the same thing? This could be something many many people face

thanks @Connoropolous that definitely helps me understand what the error message means. I’m still a bit confused about how this applies in my case…

the call that is triggering this error, is a holochain function ‘create_cap_grant’. The workflow for this function is:

  1. generates a secret with built-in function generate_cap_secret
  2. create the cap grant with built-in function create_cap_grant
  3. use call_remote to sent the grant to the grantee

So, just within the normal workflow of creating a cap grant, I have to call at least 3 other functions. Could it be these that are causing the issue?

It’s weird that this doesn’t cause any problem in tryorama test if so, isn’t it?

Thanks - alex.

btw I noticed that the call_remote function in p2p.rs only permits AgentPubKey, and NOT AgentPubKey64:

pub fn call_remote<I>(
    agent: AgentPubKey,
    zome: ZomeName,
    fn_name: FunctionName,
    cap_secret: Option<CapSecret>,
    payload: I,
)

In which case there must be some established method of passing the AgentPubKey back from the UI, for a call_remote execution using only buffer or uint8array. Are there any examples of using capgrants in a UI? I looked in elemental-chess, holochain open-dev and the devcamp project but can’t find any references.

Since I can’t quite follow, maybe paste in a code block of the rust code for the function? Most likely way i can help

thank you - here’s the function generating the error in UI:

// creates assigned cap grant for users to access specified remote function
// HeaderAndEntryHash is returned so it can be kept and used later for delete_cap_grant
pub fn create_capgrant(access: GrantCapAccess) -> ExternResult<HeaderAndEntryHash> {
    // Create function map of cap grant
    let mut functions: GrantedFunctions = BTreeSet::new();
    let this_zome = zome_info()?.name;
    // remote function to access is passed from GrantCapAccess input
    functions.insert((this_zome.clone(), access.function.into()));

    // Create the cap grant and commit for current agent
    let cap_secret = generate_cap_secret()?;

    let a: HeaderHash = create_cap_grant(CapGrantEntry {
        tag: "cap_grant".into(),
        access: CapAccess::from((cap_secret, access.agent.clone())),
        functions,
    })?;
    let result = HeaderAndEntryHash {
        header_hash: a,
    };

    // Call the zome of target agent and give them the generated cap secret
    call_remote(
        access.agent.clone(),
        zome_info()?.name,
        "receive_cap_access".into(),
        None,
        CapReceive {
            cap_secret: cap_secret,
            from_agent: agent_info()?.agent_initial_pubkey
        },
    )?;
    Ok(result)
}

input struct GrantCapAccess is:

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct GrantCapAccess {
    pub function: String,
    pub agent: AgentPubKey
}

You’re not passing the same agentpubkey in as a value as the same agent who is calling the function are you? E.g. caller and callee are actually two separate agents right? Because if not that could explain the issue.

hey @Connoropolous - I’m ashamed to admit that I was indeed sending the same agentpubkey :confused: Well that explains why tryorama was working fine - I was getting in a bit of a mess with handling profiles in the front end and that was the result…
that was quite a dumb mistake, but I wouldn’t have realised (in a reasonable amount of time) without your help. Thanks so much!

Once I saw the code that seemed to be the only explanation, and it’s the call_remote which opens up the gateway to a HeadMoved error since it spawns a new “atomic commit space” which is the “scratchpad” that zome calls write all entries to until the zome call has completed. A call_remote opens a new scratchpad, because it’s like a separate zome call.

All good! Glad you could get past it!