Search code examples
phpjsonbitcoind

Bitcoind returns error "JSON value is not an array as expected", using easybitcoin.php to call sendmany()


I am creating a php script to use the sendmany() call to bitcoind. After some database calisthenics involving hitting three tables for permissions, checking user privileges and ensuring the send amounts are correct and there are enough bitcoins on the server, I wind up with the following array to send bitcoins to:

Array
(
    [0] => Array
        (
            [coinadd] => mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw
            [amount] => 0.21445033
        )

    [1] => Array
        (
            [coinadd] => 2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe
            [amount] => 0.02588679
        )

    [2] => Array
        (
            [coinadd] => 2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK
            [amount] => 0.02601681
        )

)

EDIT: I changed the below foreach into a much simpler version. I would do a striketrhough to show it was changed, but can"t find how to strikethrough.

$max = count($paynow);
    $b=1;
    $amount = 0;
    $emit = '{"';
    foreach($paynow as $key => $val){
        foreach($val as $k => $v){
            $emit .= "$v";
            if($b <= $max){
                if($k == 'coinadd'){
                    $emit .= '":';
                } elseif($k == 'amount') {
                    $amnt = $amount += $v;
                    if($b !== $max){
                        $emit .= ', "'; 
                    }               
                }
            }
        }
        $b++;
    }
    $emit .= "}";

The above foreach takes the $paytoo array and generates the following json string:

{
"mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw":0.21445033, "2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe":0.02588679, "2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK":0.02601681
}

This string passes the JSON lint test on jsonlint.com

I then decode the string to create an array.

$send = json_decode($emit,true);

Edit; Now the new foreach generates the below array directly, no json string, just direct. Seems much cleaner than before.

foreach($paydata as $pay){
    $mrules = getmerchrules($pay['merchant_id']);
    $coinadd = get_merch_address_to_send_to($pay['merchant_id']);
    if($mrules['autopay'] == 'yes'){
        if($pay['balance'] > $mrules['minpay']){
            if($coinadd !== ''){
                $paynow[$coinadd['coinadd']] = $pay['balance'];
            }
        }
    }
}

Array
(
    [mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw] => 0.21445033
    [2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe] => 0.02588679
    [2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK] => 0.02601681
)

So far so good.

Now on to the RPC call

$sent = $bitcoin->sendmany( "", $send, 1, "", "", 1, 1, "CONSERVATIVE" );
$err = $bitcoin->error;

EDIT: Some fancy echoing gets me this string which is what is actually sent to the bitcoind server through curl. This string also passes the jsonlint.com test.

Array
(
    [19913] => 1
    [52] => 1
    [68] => 10
    [10023] => Array
        (
            [0] => Content-type: application/json
        )

    [47] => 1
    [10015] => {"method":"sendmany","params":["","{\"mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw\":\"0.24020698\",\"2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe\":\"0.02588679\",\"2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK\":\"0.02601681\"}",1],"id":4}
)

EDIT: STILL NO CHANGE

Array
(
    [result] => 
    [error] => Array
        (
            [code] => -1
            [message] => JSON value is not an object as expected
        )

    [id] => 4
)

Aaaand Kablooie! I get the following error from Bitcoind:

"JSON value is not an array as expected"

If I turn the JSON string into an object, then the error switches to

"JSON value is not an object as expected".

This snippet of code is from the library's __call method in easybitcoin.php

// If no parameters are passed, this will be an empty array
$params = array_values($params);

...

// Build the request, it's ok that params might have any empty array
$request = json_encode(array(
    'method' => $method,
    'params' => $params,
    'id'     => $this->id
));

Other than slitting my wrists and offering my blood to the programming gods, I've done everything I can think of. Can anyone spot what I am doing wrong here?

For anyone wondering, this command worked on ./bitcoin-cli

./bitcoin-cli sendmany "" "{\"mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw\":0.21445033, \"2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe\":0.02588679, \"2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK\":0.02601681}" 1

Bitcoind response is a txid number

f4c443881a40054efbd5c3064268a91253f4cb2f7ba8caca96878d0dec46d774

Sorry about the multiple edits, didn't realize that Enter key submits.


Solution

  • I found the problem.

    I am going to place it as an answer here in the event someone else has this issue.

    foreach($paydata as $pay){
        $mrules = getmerchrules($pay['merchant_id']);
        $coinadd = get_merch_address_to_send_to($pay['merchant_id']);
        if($mrules['autopay'] == 'yes'){
            if($pay['balance'] > $mrules['minpay']){
                if($coinadd !== ''){
                    $paynow[$coinadd['coinadd']] = $pay['balance'];
                }
            }
        }
    }
    
    Array
    (
        [mteCLqiEK7v5d3YbDQtxj8oKcdhtHRtXcw] => 0.21445033
        [2N5aa9FBxGf5xmeLiDz1yJVNYdsfK9GUWWe] => 0.02588679
        [2Muf4WEzFqNviURTdvkGSswHyrgMzR8optK] => 0.02601681
    )
    

    At the point in the code that the array above is created, there is no need to do anything else. The problem was that I was converting this array into a json object to send to easybitcoin.php.

    What easybitcoin.php expects is an array. So feeding it the array by itself worked. Even though this can'be blamed on anyone but me, the documentation out there is pretty sketchy. So once and for all, I am going to leave this here and hopefully it will save someone some time in the future.

    $sent = $bitcoin->sendmany( "", $send, 1, "", "", 1, 1, "CONSERVATIVE" );
    

    Where $send is a simple array as shown above. No other formatting needed. No double quotes, nothing, just pass the array. Yes, stupid, I know. But here we are. Thanks to all those who looked.