I'm trying to validate a signed message using a smart contract running on the TRON network.
I've tried a few different methods but all failed:
Based on this article I've deployed the following smart contract:
contract Verifier {
function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
return ecrecover(msgHash, v, r, s);
}
function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
return ecrecover(msgHash, v, r, s) == _addr;
}
}
And the following client (js) code:
let contract = await tronWeb.contract().at(contract_address);
let msg = tronWeb.sha3('This is my message');
let signature = await tronWeb.trx.sign(msg);
var r = signature.substr(0, 66);
var s = "0x" + signature.substr(66, 64);
var v = "0x" + signature.substr(signature.length - 2);
let hexAddress = await contract.recoverAddr(msg, v, r, s).call();
But got back a wrong address.
Based on this article I've deployed the following smart contract:
contract Verifier {
//return the address according to the signature and and the data
function validate(bytes32 hash, bytes signature)
public
pure
returns (address){
bytes memory signedString = signature;
bytes32 r = convertToBytes32(slice(signedString, 0, 32));
bytes32 s = convertToBytes32(slice(signedString, 32, 32));
byte v1 = slice(signedString, 64, 1)[0];
uint8 v = uint8(v1) + 27;
return ecrecover(hash, uint8(r), s, bytes32(v));
}
//slice function
function slice(bytes memory data, uint start, uint len)
private
pure
returns (bytes){
bytes memory b = new bytes(len);
for(uint i = 0; i < len; i++){
b[i] = data[i + start];
}
return b;
}
//convert bytes to bytes32
function convertToBytes32(bytes memory source)
private
pure
returns (bytes32 result) {
assembly {
result := mload(add(source, 32))
}
}
}
And the following client (js) code:
let contract = await tronWeb.contract().at(contract_address);
let msg = tronWeb.sha3('Hello World');
let signature = await tronWeb.trx.sign(msg);
let hexAddress = await contract.validate(msg, signature).call();
Still got back a wrong address.
I managed to sign and recover an address using pure js code based on this:
const ethers = tronWeb.utils.ethersUtils;
let signingKey = new ethers.SigningKey(tronWeb.defaultPrivateKey);
let message = "This is some message";
let messageBytes = ethers.toUtf8Bytes(message);
let messageDigest = ethers.keccak256(messageBytes);
let signature = signingKey.signDigest(messageDigest);
let recovered = ethers.recoverAddress(messageDigest, signature);
console.log("Recovered address: " + recovered);
How can I sign a message using a js code and recover using a smart contract? What am I missing?
I got it.
The smart contract code:
contract Verifier {
function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
return ecrecover(msgHash, v, r, s);
}
function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
return ecrecover(msgHash, v, r, s) == _addr;
}
}
The client code:
const ethers = tronWeb.utils.ethersUtils;
let contract = await tronWeb.contract().at(contract_address);
let signingKey = new ethers.SigningKey(tronWeb.defaultPrivateKey);
let message = "This is some message";
let messageBytes = ethers.toUtf8Bytes(message);
let messageDigest = ethers.keccak256(messageBytes);
let signature = signingKey.signDigest(messageDigest);
let hexAddress = await contract.recoverAddr(messageDigest, signature.v, signature.r, signature.s).call();
Related
I have to create a simple web server in Swift or Obj-C for an iOS application.
In fact it has to be the simplest web server ever because it just has to create a socket or whatever to listen to a web page request.
Then it has to provide the HTML string when the request comes.
That's all, no other feature from a real web server needed.
It has to respond only to a single type of requests
localhost:port/page_number.html
or with different alias, like
alias/page_number.html
Is it possible?
I read an example for Mac OS, with very short source code, but I also found examples for iOS that have many source code files and they are not simple at all.
The Mac OS example leverages Darwin library. Maybe it is so powerful that a simple web server is possible with a few instructions.
It is from Tiny http server engine written in Swift programming language
Here is the code:
import Darwin.C
let zero = Int8(0)
let transportLayerType = SOCK_STREAM // TCP
let internetLayerProtocol = AF_INET // IPv4
let sock = socket(internetLayerProtocol, Int32(transportLayerType), 0)
let portNumber = UInt16(4000)
let socklen = UInt8(socklen_t(MemoryLayout<sockaddr_in>.size))
var serveraddr = sockaddr_in()
serveraddr.sin_family = sa_family_t(AF_INET)
serveraddr.sin_port = in_port_t((portNumber << 8) + (portNumber >> 8))
serveraddr.sin_addr = in_addr(s_addr: in_addr_t(0))
serveraddr.sin_zero = (zero, zero, zero, zero, zero, zero, zero, zero)
withUnsafePointer(to: &serveraddr) { sockaddrInPtr in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
bind(sock, sockaddrPtr, socklen_t(socklen))
}
listen(sock, 5)
print("Server listening on port \(portNumber)")
repeat {
let client = accept(sock, nil, nil)
let html = "<!DOCTYPE html><html><body style='text-align:center;'><h1>Hello from <a href='https://swift.org'>Swift</a> Web Server.</h1></body></html>"
let httpResponse: String = """
HTTP/1.1 200 OK
server: simple-swift-server
content-length: \(html.count)
\(html)
"""
httpResponse.withCString { bytes in
send(client, bytes, Int(strlen(bytes)), 0)
close(client)
}
} while sock > -1
But I know that iOS is advanced too, so maybe there is a very compact code to create that web server minimal capability on iOS.
Here is a very basic and simplified http server implementation in Swift that might be enough for your case if you do not want to use external libraries:
class PicoHttpServer {
private static var serverSocket: Int32?
private static let queue = DispatchQueue(label: "com.pico.http.server.queue")
private static let semaphore = DispatchSemaphore(value: 1)
static func httpOkResponse(html: String) -> String {
return "HTTP/1.1 200 OK\r\nServer: PicoHttpServer\r\nContent-Length: \(html.count)\r\n\r\n\(html)"
}
static func start(port: UInt16 = 7000, address: UInt32 = INADDR_LOOPBACK, requestHandler: #escaping ((String) -> String)) {
semaphore.wait()
let started = serverSocket != nil
semaphore.signal()
if started {
return
}
queue.async {
realStart(port: port, address: address, requestHandler: requestHandler)
}
}
static func stop() {
semaphore.wait()
if let serverSocker = serverSocket {
close(serverSocker)
}
serverSocket = nil
semaphore.signal()
}
private static func realStart(port: UInt16, address: UInt32, requestHandler: ((String) -> String)) {
let tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
if tcpSocket == -1 {
return
}
serverSocket = tcpSocket
var reuseOn = Int32(1)
setsockopt(tcpSocket, SOL_SOCKET, SO_REUSEADDR, &reuseOn, socklen_t(MemoryLayout.size(ofValue: reuseOn)))
var socketAddress = sockaddr_in()
socketAddress.sin_family = sa_family_t(AF_INET)
socketAddress.sin_port = port.bigEndian
socketAddress.sin_addr = in_addr(s_addr: address.bigEndian)
socketAddress.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
let socklen = UInt8(socklen_t(MemoryLayout<sockaddr_in>.size))
let bindResult = withUnsafePointer(to: &socketAddress) { sockaddrInPtr -> Int32 in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
return bind(tcpSocket, sockaddrPtr, socklen_t(socklen))
}
if bindResult == -1 {
return
}
let listenResult = listen(tcpSocket, 5)
if listenResult == -1 {
return
}
print("Server started")
while(true) {
semaphore.wait()
let stopped = serverSocket == nil
semaphore.signal()
if stopped {
break
}
let mtu = 65536
let client = accept(tcpSocket, nil, nil)
if client == -1 {
continue
}
var buffer = Data(repeating: 0, count: mtu)
let readResult = buffer.withUnsafeMutableBytes { pointer in
return read(client, pointer.baseAddress, mtu)
}
if readResult == -1 {
continue
}
let clientData = buffer.subdata(in: 0..<readResult)
let clientRequest = String(data: clientData, encoding: .utf8) ?? ""
let response = requestHandler(clientRequest)
response.withCString { bytes in
write(client, bytes, Int(strlen(bytes)))
close(client)
}
}
print("Server stopped")
}
}
Then you can use it as below to response with different html for each page number:
PicoHttpServer.start { request in
if request.hasPrefix("GET /1.html") {
return PicoHttpServer.httpOkResponse(html: "<html><body>Page 1</body></html>")
} else if request.hasPrefix("GET /2.html") {
return PicoHttpServer.httpOkResponse(html: "<html><body>Page 2</body></html>")
} else {
return PicoHttpServer.httpOkResponse(html: "<html><body>Other page</body></html>")
}
}
Note that if you want to open this from your app in Safari as you wrote in the comment to the question then you will probably also need to create a background task with UIApplication.shared.beginBackgroundTask so that your app can run this server at least for a moment when your iPhone app goes to background.
I'm using SwiftSoup in combination with Codable to get the correct element(s) and parse the data. However, I receive this error:
JSON decode failed: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.})))
I've looked online, ensure my data matches correctly, even change the expected types from Int to String but got an error stating an Int was expected.
This is the data I am receiving and can print in the console:
data -
{"test":0,"ppace":85,"pshooting":92,"ppassing":91,"pdribbling":95,"pdefending":38,"pphysical":65,"acceleration":91,"sprintspeed":80,"agility":91,"balance":95,"reactions":94,"ballcontrol":96,"dribbling":96,"positioning":93,"finishing":95,"shotpower":86,"longshotsaccuracy":94,"volleys":88,"penalties":75,"interceptions":40,"headingaccuracy":70,"marking":32,"standingtackle":35,"slidingtackle":24,"vision":95,"crossing":85,"freekickaccuracy":94,"shortpassing":91,"longpassing":91,"curve":93,"jumping":68,"stamina":72,"strength":69,"aggression":44,"composure":96}
This is my function:
func parseData() {
do {
let html = try String(contentsOf: url!, encoding: String.Encoding.ascii)
let doc: Document = try! SwiftSoup.parse(html)
let elements = try doc.getAllElements()
for element in elements {
switch element.id() {
case "player_stats_json":
let content = try! element.getElementsContainingText("ppace").text()
print(content.utf8)
let jsonData = content.data(using: .utf8)
do {
self.player = try JSONDecoder().decode(PlayerModel.self, from: Data(jsonData!))
} catch let jsonError as NSError {
print("JSON decode failed: \(jsonError)")
print("data - \(content)")
}
default:
break
}
}
} catch Exception.Error(type: let type, Message: let message) {
print(type)
print(message)
} catch {
print("")
}
}
And this is my model file:
struct PlayerModel: Codable {
var test: Int
var ppace: Int
var pshooting: Int
var ppassing: Int
var pdribbling: Int
var pdefending: Int
var pphysical: Int
var acceleration: Int
var sprintspeed: Int
var agility: Int
var balance: Int
var reactions: Int
var ballcontrol: Int
var dribbling: Int
var positioning: Int
var finishing: Int
var shotpower: Int
var longshotsaccuracy: Int
var volleys: Int
var penalties: Int
var interceptions: Int
var headingaccuracy: Int
var marking: Int
var standingtackle: Int
var slidingtackle: Int
var vision: Int
var crossing: Int
var freekickaccuracy: Int
var shortpassing: Int
var longpassing: Int
var curve: Int
var jumping: Int
var stamina: Int
var strength: Int
var aggression: Int
var composure: Int
}
I've double and tripled checked the variable names match up with each key. I've pasted the outputted data in the console in an Online JSON validator, and no errors appear. I'm genuinley left scratching my head right now, because I can't understand where I've gone wrong.
I still have no idea whats wrong with your parsing. I've managed to parse your html but I have no idea why when trying to use Int instead of Uint8 it kept failing to return the right values. This is what worked for me:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
struct PlayerModel: Codable {
let test: UInt8
let ppace: UInt8
let pshooting: UInt8
let ppassing: UInt8
let pdribbling: UInt8
let pdefending: UInt8
let pphysical: UInt8
let acceleration: UInt8
let sprintspeed: UInt8
let agility: UInt8
let balance: UInt8
let reactions: UInt8
let ballcontrol: UInt8
let dribbling: UInt8
let positioning: UInt8
let finishing: UInt8
let shotpower: UInt8
let longshotsaccuracy: UInt8
let volleys: UInt8
let penalties: UInt8
let interceptions: UInt8
let headingaccuracy: UInt8
let marking: UInt8
let standingtackle: UInt8
let slidingtackle: UInt8
let vision: UInt8
let crossing: UInt8
let freekickaccuracy: UInt8
let shortpassing: UInt8
let longpassing: UInt8
let curve: UInt8
let jumping: UInt8
let stamina: UInt8
let strength: UInt8
let aggression: UInt8
let composure: UInt8
}
let url = URL(string:"https://www.futbin.com/21/player/541/lionel-messi")!
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, let html = String(data: data, encoding: .utf8) else { return }
if let start = html.range(of: #"<div style="display: none;" id="player_stats_json">"#)?.upperBound,
let end = html[start...].range(of: #"</div>"#)?.lowerBound {
let json = html[start..<end]
do {
let player = try JSONDecoder().decode(PlayerModel.self, from: Data(json.utf8))
print(player)
} catch {
print(error)
}
}
}.resume()
This will print
PlayerModel(test: 0, ppace: 85, pshooting: 92, ppassing: 91,
pdribbling: 95, pdefending: 38, pphysical: 65, acceleration: 91,
sprintspeed: 80, agility: 91, balance: 95, reactions: 94, ballcontrol:
96, dribbling: 96, positioning: 93, finishing: 95, shotpower: 86,
longshotsaccuracy: 94, volleys: 88, penalties: 75, interceptions: 40,
headingaccuracy: 70, marking: 32, standingtackle: 35, slidingtackle:
24, vision: 95, crossing: 85, freekickaccuracy: 94, shortpassing: 91,
longpassing: 91, curve: 93, jumping: 68, stamina: 72, strength: 69,
aggression: 44, composure: 96)
I have a simple solidity code
pragma solidity >0.4.24;
contract Store {
event ItemSet(bytes32 key, bytes32 value);
string public version;
mapping (bytes32 => bytes32) public items;
constructor(string memory _version) public {
version = _version;
}
function setItem(bytes32 key, bytes32 value) external {
items[key] = value;
emit ItemSet(key, value);
}
}
This is the Golang code to call the contract method
auth := bind.NewKeyedTransactor(privateKey)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(0) // in wei
auth.GasLimit = uint64(300000) // in units
auth.GasPrice = big.NewInt(0)
address := common.HexToAddress("0xe17a5308f99584834823d2b27B328cb6abaabF11")
instance, err := store.NewStore(address, client)
if err != nil {
log.Fatal(err)
}
key := [32]byte{}
value := [32]byte{}
copy(key[:], []byte("foo"))
copy(value[:], []byte("bar"))
tx, err := instance.SetItem(auth, key, value)
if err != nil {
log.Fatal(err)
}
fmt.Printf("tx sent: %s", tx.Hash().Hex())
result, err := instance.Items(nil, key)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result[:]))
instance.SetItem(auth, key, value) Calling the SetItem method is successful but when I try to get the Items
tx sent: 0xb8578fb80f7f49d833e05413c957fbd353babe1a993ed96c26b890a1f9cf60fd <-- This hash is for the SetItem
I am getting this error
2019/11/20 23:14:13 abi: attempting to unmarshall an empty string while arguments are expected
Please help on this if anyone has any solution please help me with this error .
You don't have Items function in your contract.
I am trying to learn how JSON-RPC works and am testing it in Go language (golang). The Go program works fine. It does what it should do. But when I try to make a raw request via telnet, it gives an error.
The working and super simple JSON-RPC server is described here:
// rpc_json_server.go
package main
import (
"log"
"net"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
)
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
type Arithmetic int // Used as RPC Service called 'Arithmetic'
type Arguments struct {
A int
B int
}
type Result int
//------------------------------------------------------------------------------
// Methods
//------------------------------------------------------------------------------
func (t *Arithmetic) Multiply(args *Arguments, res *Result) error {
*res = Result(args.A * args.B)
return nil
}
//------------------------------------------------------------------------------
func main() {
var srv *rpc.Server
var err error
var arith *Arithmetic
var listener net.Listener
var codec rpc.ServerCodec
var srv_conntype, srv_host, srv_port, srv_addr, srv_path string
var srv_debugPath string
var connection net.Conn
srv_conntype = "tcp"
srv_host = "0.0.0.0"
srv_port = "3000"
srv_addr = srv_host + ":" + srv_port
srv_path = "/"
srv_debugPath = "/debug"
// Create Server, register Service
srv = rpc.NewServer()
arith = new(Arithmetic)
err = srv.Register(arith)
if err != nil {
log.Fatalf("Error. Service Format is not correct. %s\r\n", err) //dbg
}
// Handle, listen
srv.HandleHTTP(srv_path, srv_debugPath)
listener, err = net.Listen(srv_conntype, srv_addr)
if err != nil {
log.Fatalf("Error. Can not listen on %s. %s\r\n", srv_addr, err) //dbg
}
log.Printf("Started RPC Handler at %s.\r\n", srv_addr) //dbg
// Serve
for {
connection, err = listener.Accept()
if err != nil {
log.Fatal(err)
}
codec = jsonrpc.NewServerCodec(connection)
go srv.ServeCodec(codec)
}
err = http.Serve(listener, nil)
if err != nil {
log.Fatalf("Serve Error. %s\r\n", err) //dbg
}
}
//------------------------------------------------------------------------------
The working and super simple JSON-RPC client's code is following:
// rpc_json_client.go
package main
import (
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
type Arithmetic int // Used as RPC Service called 'Arithmetic'
type Arguments struct {
A int
B int
}
type Result int
//------------------------------------------------------------------------------
// Methods
//------------------------------------------------------------------------------
func main() {
var err error
var srv_conntype, srv_host, srv_port, srv_addr string
//var srv_path string
var client *rpc.Client
var args Arguments
var result Result
var serviceName, methodName, funcName string
var connection net.Conn
srv_conntype = "tcp"
srv_host = "0.0.0.0"
srv_port = "3000"
srv_addr = srv_host + ":" + srv_port
//srv_path = "/"
// Connect to RPC Server
connection, err = net.Dial(srv_conntype, srv_addr)
if err != nil {
log.Fatalf("Error. Can not connect to %s. %s\r\n", srv_addr, err) //dbg
}
defer connection.Close()
// Client
client = jsonrpc.NewClient(connection)
// Prepare Call
serviceName = "Arithmetic"
methodName = "Multiply"
funcName = serviceName + "." + methodName
args.A = 7
args.B = 8
// Call remote Procedure
err = client.Call(funcName, args, &result)
if err != nil {
log.Fatalf("Error. %s\r\n", err) //dbg
}
// Show Results
fmt.Printf("[%d; %d] -> [%d].\r\n", args.A, args.B, result) //dbg
}
Once again. This golang program works fine.
But the next thing I cannot understand.
telnet localhost 3000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{
"jsonrpc":"2.0",
"method":"Arithmetic.Multiply",
"params": { "A": 5, "B": 6 },
"id":1
}
{"id":1,"result":null,"error":"json: cannot unmarshal object into Go value of type [1]interface {}"}
Please, give me some advice or the reason for such an error. What is wrong in the raw request?
Thanks in advance!
Your code seems fine.
But in the request, params is expected to be an array containing the actual parameters.
Try with the following payload and it should work:
{
"jsonrpc":"2.0",
"method":"Arithmetic.Multiply",
"params": [ { "A": 5, "B": 6 } ],
"id":1
}
(Note the "[" and "]" enclosing the actual param)
Let's say I have a program with the following declaration:
std::vector<std::vector<std::vector<std::string> *> > s;
Now I would like to tokenize this, cut it in parts:
std vector
std vector
std vector pointer
std string
When going through the source-code, this example will give me a VarDecl. If I understood it correctly, this VarDecl contains the whole declaration. Now I think the next step is invoking getType() on that VarDecl. But then what? I expected a method that would return e.g. an iterator or so.
Below you'll see what I have. This works fine for e.g. "int i" or "const char *const i = NULL;" even for "const std::string l = "12";" but "std::vector *> > s;" results in an "int"?(!?).
void dissectType(ASTContext *const Context, const QualType x)
{
if (x.isNull())
return;
QualType type = x.getNonReferenceType();
for(;!type.isNull();) {
if (type.hasQualifiers()) {
Qualifiers q = type.getQualifiers();
if (q.hasConst())
printf("const ");
if (q.hasVolatile())
printf("volatile ");
if (q.hasRestrict())
printf("restrict ");
}
const Type *t = type.getTypePtr();
if (!t) {
printf("null?\n");
break;
}
else if (t -> isPointerType())
printf("* ");
else if (t -> isFundamentalType()) {
std::string curType = type.getUnqualifiedType().getAsString();
printf("%s\n", curType.c_str());
break; // should be last entry in this chain
}
type = type->getPointeeType();
}
}