1

I am writing a client that makes requests to the DA Ledger. I am following the advice I received in a previous post Doing CRUD on the DA Ledger through a gRPC client.
I need to run the 'GetTransactions' rpc. Doing so requires GetTransactionsRequest object. The GetTransactionsRequest object has a required property called 'filter' which is of type TransactionFilter. I am having trouble creating a transaction filter to meet my needs. The .proto file for it is:

// Used for filtering Transaction and Active Contract Set streams.
// Determines which on-ledger events will be served to the client.

message TransactionFilter {

  // Keys of the map determine which parties' on-ledger transactions are being queried.
  // Values of the map determine which events are disclosed in the stream per party.
  // At the minimum, a party needs to set an empty Filters message to receive any events.
  // Required
  map<string, Filters> filters_by_party = 1;
}

the one and only field of 'filters_by_party' is required. Setting this field in php requires the following function:

/**
     * Keys of the map determine which parties' on-ledger transactions are being queried.
     * Values of the map determine which events are disclosed in the stream per party.
     * At the minimum, a party needs to set an empty Filters message to receive any events.
     * Required
     *
     * Generated from protobuf field <code>map<string, .com.digitalasset.ledger.api.v1.Filters> filters_by_party = 1;</code>
     * @param array|\Google\Protobuf\Internal\MapField $var
     * @return $this
     */
    public function setFiltersByParty($var)
    {
        $arr = GPBUtil::checkMapField($var, \Google\Protobuf\Internal\GPBType::STRING, \Google\Protobuf\Internal\GPBType::MESSAGE, \Com\Digitalasset\Ledger\Api\V1\Filters::class);
        $this->filters_by_party = $arr;

        return $this;
    }

The php function for setting up a values in a mapFiled object is:

/**
     * Assign the element at the given key.
     *
     * This will also be called for: $arr[$key] = $value
     *
     * @param object $key The key of the element to be fetched.
     * @param object $value The element to be assigned.
     * @return void
     * @throws ErrorException Invalid type for key.
     * @throws ErrorException Invalid type for value.
     * @throws ErrorException Non-existing key.
     */
    public function offsetSet($key, $value)
    {
        $this->checkKey($this->key_type, $key);

        switch ($this->value_type) {
            case GPBType::SFIXED32:
            case GPBType::SINT32:
            case GPBType::INT32:
            case GPBType::ENUM:
                GPBUtil::checkInt32($value);
                break;
            case GPBType::FIXED32:
            case GPBType::UINT32:
                GPBUtil::checkUint32($value);
                break;
            case GPBType::SFIXED64:
            case GPBType::SINT64:
            case GPBType::INT64:
                GPBUtil::checkInt64($value);
                break;
            case GPBType::FIXED64:
            case GPBType::UINT64:
                GPBUtil::checkUint64($value);
                break;
            case GPBType::FLOAT:
                GPBUtil::checkFloat($value);
                break;
            case GPBType::DOUBLE:
                GPBUtil::checkDouble($value);
                break;
            case GPBType::BOOL:
                GPBUtil::checkBool($value);
                break;
            case GPBType::STRING:
                GPBUtil::checkString($value, true);
                break;
            case GPBType::MESSAGE:
                if (is_null($value)) {
                  trigger_error("Map element cannot be null.", E_USER_ERROR);
                }
                GPBUtil::checkMessage($value, $this->klass);
                break;
            default:
                break;
        }

        $this->container[$key] = $value;
    }

How do I, for example, set up the parties name 'dealer1' and 'dealer2' as my parties for filters_by_party. I tried the following code:

$parties= new Google\Protobuf\Internal\MapField(Google\Protobuf\Internal\GPBType::STRING,Google\Protobuf\Internal\GPBType::MESSAGE); 
$parties->offsetSet(0,"dealer1"); 
$parties->offsetSet(1,"dealer2"); 

results in the following error:

PHP Fatal error:  Given value is not message. in /home/vantage/damlprojects/loaner_car/php/ledger_client.php on line 85

I don't understand why a 'message' is required by the filter_by_party 'set' function. I don't know how to write the dealer name in the form of a 'meessage'. It seems doing something that should be simple is very complicated. What is the correct way to set up the input $var to the 'setFiltersByParty' function?

Meyer Auslander
  • 349
  • 1
  • 10

2 Answers2

1

Maybe you can find some information here: https://developers.google.com/protocol-buffers/docs/reference/php-generated#fields

For map field, I guess it would be something looks like:

$m->getFiltersByParty()["string"] = new Filters();
Zhouyihai Ding
  • 253
  • 1
  • 5
  • I need to set the filters by party, not get the filters by party. In order to set them do I not need to call the function setFiltersByParty(). If so I need to create a new MapField object, set it's parameters, and then pass it in to setFiltersByParty(). I don't see any online docs on how to set the fields of a MapField field. – Meyer Auslander Mar 11 '19 at 16:04
0

The code for setting up 'dealer1' and dealer2' should look as follows:

$parties= new Google\Protobuf\Internal\MapField(Google\Protobuf\Internal\GPBType::STRING,
   Google\Protobuf\Internal\GPBType::MESSAGE, "Com\Digitalasset\Ledger\Api\V1\Filters");

$partyIdentifier = new Com\Digitalasset\Ledger\Api\V1\Identifier();
$partyIdentifier->setPackageId($the_package_id); //last one from ListPackages()
$partyIdentifier->setEntityName("<Module>");  //from DAML code
$partyIdentifier->setModuleName("<Template>"); //from DAML code


$partyInclusiveFilters = new Com\Digitalasset\Ledger\Api\V1\InclusiveFilters();
$partyInclusiveFilters->setTemplateIds(array($partyIdentifier));

$partyFilters = new Com\Digitalasset\Ledger\Api\V1\Filters();
$partyFilters->setInclusive($partyInclusiveFilters);

$parties->offsetSet("dealer1",$partyFilters);
$parties->offsetSet("dealer2",$partyFilters);

It is important to set the third parameter of the MapField constructor to "Com\Digitalasset\Ledger\Api\V1\Filters". As the protobuf file suggests:

message TransactionFilter {

          // Keys of the map determine which parties' on-ledger transactions are being queried.
          // Values of the map determine which events are disclosed in the stream per party.
          // At the minimum, a party needs to set an empty Filters message to receive any events.
          // Required
          map<string, Filters> filters_by_party = 1;
        }

The filters_by_party is MapField that has a value_type of 'Filter'. 'Filter' is a type of message (see your transaction_filter.proto file), therefore the MapField constructor needs to know what type of message it is.

The dealer name is not being written in the form of a "message" but rather it is a key_value in the the 'filters_by_party' MapField that corresponds to a 'Filter' object. And a 'Filter' is a type of message. I guess 'simple' is a relative term.

Meyer Auslander
  • 349
  • 1
  • 10