Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: add warning in case of using msg.pubkey() without AbiHeader pubkey #63

Open
unboxedtype opened this issue Aug 12, 2021 · 2 comments

Comments

@unboxedtype
Copy link

Hi!

Today, I spent several hours trying to find out why the message I sign with some key fail to pass the signature check in my contract, until found the reason, stated in the API documentation:

"Returns sender's public key, obtained from the body of the external inbound message. If the message is not signed, msg.pubkey() returns 0. If the message is signed and message header (pragma AbiHeader) does not contain pubkey then msg.pubkey() is equal to tvm.pubkey()."

As for me, this behavior feels a bit counter intuitive. Maybe it would be better to show a warning in case of using the msg.pubkey() without pragma AbiHeader pubkey?

@IgorKoval
Copy link
Collaborator

Could you explain in detail what the problem was? Or could you show the wrong/correct code?

@ilyar
Copy link

ilyar commented Feb 15, 2022

Compiler 0.57.3, Linker 0.14.37, SE 0.29.0

To test this behavior, I use the code src/App.sol:

pragma ton-solidity >= 0.57.3;
pragma AbiHeader time;
pragma AbiHeader pubkey;
pragma AbiHeader expire;
pragma msgValue 42.001 ever;

contract App {
    constructor() onlyOwner messageLog("constructor") public { stash = 42; }
    uint public stash;
    function put() accept internalMsg messageLog("put") external { stash += 42; }
    function make() onlyOwner externalMsg messageLog("make") external { App(address(this)).put(); }
    modifier onlyOwner {
        require(tvm.pubkey() != 0, 101);
        require(msg.pubkey() == tvm.pubkey(), 102);
        tvm.accept();
        _;
    }
    modifier accept {
        tvm.accept();
        _;
    }
    modifier messageLog(string method) {
        tvm.log(format(
            "App::{} SI={} IM={} EM={} TT={} V={} DB={} At={} PK={:x}",
            method,
            msg.hasStateInit ? "Y" : "N",
            msg.isInternal ? "Y" : "N",
            msg.isExternal ? "Y" : "N",
            msg.isTickTock ? "Y" : "N",
            msg.value,
            msg.data.bits(),
            msg.createdAt,
            msg.pubkey()
        ));
        _;
    }
}

run.sh

#!/usr/bin/env bash

set -o errexit

npx everdev se reset
rm -fr build build.log

signer="$(npx everdev signer list | grep Default | cut -d' ' -f1)"
npx everdev signer info "${signer}" | jq .keys.public

# Deploy
npx everdev sol compile --code --output-dir build src/App.sol
npx everdev contract deploy --value 1000000000000 build/App

# Interact
npx everdev contract run build/App make
npx everdev contract run-local build/App stash
docker exec "$(npx everdev se info | tail -n +3 | cut -d' ' -f21)" cat /ton-node/log/tvm.log | grep App

The logs show that the public key is transmitted on the external message and is not transmitted on the internal:

App::constructor SI=Y IM=N EM=Y TT=N V=0 DB=898 At=0 PK=deb9e...
App::make SI=N IM=N EM=Y TT=N V=0 DB=898 At=0 PK=deb9e...
App::put SI=N IM=Y EM=N TT=N V=42000000000 DB=32 At=1644909519 PK=0

If you remove all headers, then the behavior changes only formsg.value

App::constructor SI=Y IM=N EM=Y TT=N V=0 DB=609 At=0 PK=deb9e...
App::make SI=N IM=N EM=Y TT=N V=0 DB=609 At=0 PK=deb9e...
App::put SI=N IM=Y EM=N TT=N V=9000000 DB=32 At=1644909342 PK=0

it turns out that msg.pubkey() is filled only for external message regardless of pragma AbiHeader pubkey

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants