'sign and verify message with solidity and python

I am trying to perform a certain action say like selling a token only when the message sent to a contract is signed by the contract owner. I knew how I would do this in js, but I am having a hard time finding a clear documentation for python. Here is what I have at the moment.

my solidity

function buy_token(string memory tokenURI, bytes memory signature) payable public{

    // Make sure this token uri is signed by the owner of the contract
    // to the recipient that is asking to buy 
    
    address signer_address = recoverSigner(keccak256(abi.encodePacked(tokenURI, msg.sender)), signature); 
    require(signer_address == minter, "NFT not authorized by this contract");
    
    require(msg.value >= cprice, "Insufficient funds to buy");

    require(minter != msg.sender, "Cant sell to owner");

    uint256 mint_id = mint(tokenURI);
    
      // transfer the token to the buyer
    _transfer(minter, msg.sender, mint_id);
}

// functions from documentatations
function recoverSigner(bytes32 message, bytes memory sig)
   public
   pure
   returns (address)
{
   uint8 v;
   bytes32 r;
   bytes32 s;
   (v, r, s) = splitSignature(sig);
   return ecrecover(message, v, r, s);
}
function splitSignature(bytes memory sig)
    public
    pure
    returns (uint8, bytes32, bytes32)
{
    require(sig.length == 65, 'Wrong byte lenght');
    
    bytes32 r;
    bytes32 s;
    uint8 v;
    assembly {
        // first 32 bytes, after the length prefix
        r := mload(add(sig, 32))
        // second 32 bytes
        s := mload(add(sig, 64))
        // final byte (first byte of the next 32 bytes)
        v := byte(0, mload(add(sig, 96)))
    }
    return (v, r, s);
}

and here is my python brownie code, which tries to emulate both a deployer and a user. The deployer signs a message and gives it to the user and the user tries to buy a token using the signed message.

from brownie import Contract, accounts
from web3.auto import w3
from eth_account.messages import encode_defunct
from eth_abi.packed import encode_abi_packed
from eth_utils import keccak
def main():
    # This part is for test in the real program the smart
    # contract would alredy be deployed
    deployer = accounts.add()
    Contract.deploy({
        'from':deployer
    })

    msg = """JSON FORMATED STRING"""
        
    hash = keccak(encode_abi_packed(['string','address'],[tokenURI, accounts[0].address]))
    message = encode_defunct(text=hash.hex())
   
    signed_message =  w3.eth.account.sign_message(message, private_key=deployer.private_key)

    signed = str(signed_message.messageHash.hex())

    tx = Contract[0].buy_token(tokenURI, signed,{'from':accounts[0], 'value': Contract[0].cprice() + 10000000000})

   print(tx.info, tx.events)

I have tried all the methods suggested in similar posts, but I couldn't get them to work, the current error is being raised by the following line.

 require(sig.length == 65, 'Wrong byte lenght');

But all the methods I try generate a signed message with a length of 66.



Solution 1:[1]

Should be signed_message.signature.hex() instead of signed_message.messageHash.hex()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Damian G?dziak